Skip to content

Commit

Permalink
Replace libdparse with DMD in AllManCheck
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladiwostok committed Aug 15, 2024
1 parent cc726c8 commit c6ae9d3
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 31 deletions.
92 changes: 61 additions & 31 deletions src/dscanner/analysis/allman.d
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@

module dscanner.analysis.allman;

import dparse.lexer;
import dparse.ast;
import dscanner.analysis.base;
import dsymbol.scope_ : Scope;

import std.algorithm;
import std.range;
import dmd.tokens : Token, TOK;
import std.algorithm : canFind, until;
import std.range : retro;

/**
Checks for the allman style (braces should be on their own line)
Expand All @@ -25,62 +22,96 @@ if (param < 0)
}
------------
*/
final class AllManCheck : BaseAnalyzer
extern (C++) class AllManCheck : BaseAnalyzerDmd
{
mixin AnalyzerInfo!"allman_braces_check";

///
this(BaseAnalyzerArguments args)
private enum string KEY = "dscanner.style.allman";
private enum string MESSAGE = "Braces should be on their own line";

private Token[] tokens;

extern (D) this(string fileName, bool skipTests = false)
{
super(fileName, skipTests);
lexFile();
checkBraces();
}

private void lexFile()
{
import dscanner.utils : readFile;
import dmd.errorsink : ErrorSinkNull;
import dmd.globals : global;
import dmd.lexer : Lexer;

auto bytes = readFile(fileName) ~ '\0';

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

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

do
{
lexer.nextToken();
tokens ~= lexer.token;
}
while (lexer.token.value != TOK.endOfFile);
}

private void checkBraces()
{
super(args);
foreach (i; 1 .. tokens.length - 1)
{
const curLine = tokens[i].line;
const prevTokenLine = tokens[i-1].line;
if (tokens[i].type == tok!"{" && curLine == prevTokenLine)
const curLine = tokens[i].loc.linnum;
const prevTokenLine = tokens[i - 1].loc.linnum;

if (tokens[i].value == TOK.leftCurly && curLine == prevTokenLine)
{
// ignore struct initialization
if (tokens[i-1].type == tok!"=")
if (tokens[i - 1].value == TOK.assign)
continue;

// ignore duplicate braces
if (tokens[i-1].type == tok!"{" && tokens[i - 2].line != curLine)
if (tokens[i - 1].value == TOK.leftCurly && tokens[i - 2].loc.linnum != curLine)
continue;

// ignore inline { } braces
if (curLine != tokens[i + 1].line)
addErrorMessage(tokens[i], KEY, MESSAGE);
if (curLine != tokens[i + 1].loc.linnum)
addErrorMessage(cast(ulong) tokens[i].loc.linnum, cast(ulong) tokens[i].loc.charnum, KEY, MESSAGE);
}
if (tokens[i].type == tok!"}" && curLine == prevTokenLine)

if (tokens[i].value == TOK.rightCurly && curLine == prevTokenLine)
{
// ignore duplicate braces
if (tokens[i-1].type == tok!"}" && tokens[i - 2].line != curLine)
if (tokens[i-1].value == TOK.rightCurly && tokens[i - 2].loc.linnum != curLine)
continue;

// ignore inline { } braces
if (!tokens[0 .. i].retro.until!(t => t.line != curLine).canFind!(t => t.type == tok!"{"))
addErrorMessage(tokens[i], KEY, MESSAGE);
if (!tokens[0 .. i].retro.until!(t => t.loc.linnum != curLine).canFind!(t => t.value == TOK.leftCurly))
addErrorMessage(cast(ulong) tokens[i].loc.linnum, cast(ulong) tokens[i].loc.charnum, KEY, MESSAGE);
}
}
}

enum string KEY = "dscanner.style.allman";
enum string MESSAGE = "Braces should be on their own line";
}

unittest
{
import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
import dscanner.analysis.helpers : assertAnalyzerWarnings;
import dscanner.analysis.helpers : assertAnalyzerWarningsDMD;
import std.format : format;
import std.stdio : stderr;

StaticAnalysisConfig sac = disabledConfig();
sac.allman_braces_check = Check.enabled;

// check common allman style violation
assertAnalyzerWarnings(q{
assertAnalyzerWarningsDMD(q{
void testAllman()
{
while (true) { /+
^ [warn]: %s +/
while (true) { // [warn]: %s
auto f = 1;
}

Expand Down Expand Up @@ -128,7 +159,7 @@ unittest
), sac);

// check struct initialization
assertAnalyzerWarnings(q{
assertAnalyzerWarningsDMD(q{
unittest
{
struct Foo { int a; }
Expand All @@ -139,12 +170,11 @@ unittest
}, sac);

// allow duplicate braces
assertAnalyzerWarnings(q{
assertAnalyzerWarningsDMD(q{
unittest
{{
}}
}, sac);


stderr.writeln("Unittest for Allman passed.");
}
6 changes: 6 additions & 0 deletions src/dscanner/analysis/run.d
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,12 @@ MessageSet analyzeDmd(string fileName, ASTCodegen.Module m, const char[] moduleN
config.has_public_example == Check.skipTests && !ut
);

if (moduleName.shouldRunDmd!AllManCheck(config))
visitors ~= new AllManCheck(
fileName,
config.allman_braces_check == Check.skipTests && !ut
);

foreach (visitor; visitors)
{
m.accept(visitor);
Expand Down

0 comments on commit c6ae9d3

Please sign in to comment.