Replace libdparse with DMD in AllManCheck (#125)

* Replace libdparse with DMD in AllManCheck

* Test assertAnalyzerDmd without writing to file

* Revert "Test assertAnalyzerDmd without writing to file"

This reverts commit 9f50f38a11d97df960c05d5a128059b13e7dcab4.

* Fix windows ci bug

---------

Co-authored-by: Eduard Staniloiu <edi33416@gmail.com>
This commit is contained in:
Vladiwostok 2024-10-09 21:16:05 +03:00 committed by Albert24GG
parent bb68206f38
commit 6c3d96e389
3 changed files with 69 additions and 37 deletions

View File

@ -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)
@ -25,50 +22,85 @@ 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;
@ -76,11 +108,10 @@ unittest
sac.allman_braces_check = Check.enabled;
// check common allman style violation
assertAnalyzerWarnings(q{
assertAnalyzerWarningsDMD(`
void testAllman()
{
while (true) { /+
^ [warn]: %s +/
while (true) { // [warn]: %s
auto f = 1;
}
@ -115,7 +146,7 @@ unittest
}
}
}
}c.format(
`c.format(
AllManCheck.MESSAGE,
AllManCheck.MESSAGE,
AllManCheck.MESSAGE,
@ -128,7 +159,7 @@ unittest
), sac);
// check struct initialization
assertAnalyzerWarnings(q{
assertAnalyzerWarningsDMD(q{
unittest
{
struct Foo { int a; }
@ -139,12 +170,11 @@ unittest
}, sac);
// allow duplicate braces
assertAnalyzerWarnings(q{
assertAnalyzerWarningsDMD(q{
unittest
{{
}}
}, sac);
stderr.writeln("Unittest for Allman passed.");
}

View File

@ -69,7 +69,6 @@ import dscanner.analysis.properly_documented_public_functions;
import dscanner.analysis.final_attribute;
import dscanner.analysis.vcall_in_ctor;
import dscanner.analysis.useless_initializer;
import dscanner.analysis.allman;
import dscanner.analysis.always_curly;
import dscanner.analysis.redundant_attributes;
import dscanner.analysis.has_public_example;
@ -668,10 +667,6 @@ BaseAnalyzer[] getAnalyzersForModuleAndConfig(string fileName,
checks ~= new UndocumentedDeclarationCheck(args.setSkipTests(
analysisConfig.undocumented_declaration_check == Check.skipTests && !ut));
if (moduleName.shouldRun!AllManCheck(analysisConfig))
checks ~= new AllManCheck(args.setSkipTests(
analysisConfig.allman_braces_check == Check.skipTests && !ut));
if (moduleName.shouldRun!IfConstraintsIndentCheck(analysisConfig))
checks ~= new IfConstraintsIndentCheck(args.setSkipTests(
analysisConfig.if_constraints_indent == Check.skipTests && !ut));

View File

@ -54,6 +54,7 @@ import dscanner.analysis.unused_variable : UnusedVariableCheck;
import dscanner.analysis.useless_assert : UselessAssertCheck;
import dscanner.analysis.useless_initializer : UselessInitializerChecker;
import dscanner.analysis.vcall_in_ctor : VcallCtorChecker;
import dscanner.analysis.allman : AllManCheck;
version (unittest)
enum ut = true;
@ -318,6 +319,12 @@ MessageSet analyzeDmd(string fileName, ASTCodegen.Module m, const char[] moduleN
config.vcall_in_ctor == 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);