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:
parent
bb68206f38
commit
6c3d96e389
|
|
@ -4,13 +4,10 @@
|
||||||
|
|
||||||
module dscanner.analysis.allman;
|
module dscanner.analysis.allman;
|
||||||
|
|
||||||
import dparse.lexer;
|
|
||||||
import dparse.ast;
|
|
||||||
import dscanner.analysis.base;
|
import dscanner.analysis.base;
|
||||||
import dsymbol.scope_ : Scope;
|
import dmd.tokens : Token, TOK;
|
||||||
|
import std.algorithm : canFind, until;
|
||||||
import std.algorithm;
|
import std.range : retro;
|
||||||
import std.range;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Checks for the allman style (braces should be on their own line)
|
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";
|
mixin AnalyzerInfo!"allman_braces_check";
|
||||||
|
|
||||||
///
|
private enum string KEY = "dscanner.style.allman";
|
||||||
this(BaseAnalyzerArguments args)
|
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)
|
foreach (i; 1 .. tokens.length - 1)
|
||||||
{
|
{
|
||||||
const curLine = tokens[i].line;
|
const curLine = tokens[i].loc.linnum;
|
||||||
const prevTokenLine = tokens[i-1].line;
|
const prevTokenLine = tokens[i - 1].loc.linnum;
|
||||||
if (tokens[i].type == tok!"{" && curLine == prevTokenLine)
|
|
||||||
|
if (tokens[i].value == TOK.leftCurly && curLine == prevTokenLine)
|
||||||
{
|
{
|
||||||
// ignore struct initialization
|
// ignore struct initialization
|
||||||
if (tokens[i-1].type == tok!"=")
|
if (tokens[i - 1].value == TOK.assign)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// ignore duplicate braces
|
// 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;
|
continue;
|
||||||
|
|
||||||
// ignore inline { } braces
|
// ignore inline { } braces
|
||||||
if (curLine != tokens[i + 1].line)
|
if (curLine != tokens[i + 1].loc.linnum)
|
||||||
addErrorMessage(tokens[i], KEY, MESSAGE);
|
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
|
// 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;
|
continue;
|
||||||
|
|
||||||
// ignore inline { } braces
|
// ignore inline { } braces
|
||||||
if (!tokens[0 .. i].retro.until!(t => t.line != curLine).canFind!(t => t.type == tok!"{"))
|
if (!tokens[0 .. i].retro.until!(t => t.loc.linnum != curLine).canFind!(t => t.value == TOK.leftCurly))
|
||||||
addErrorMessage(tokens[i], KEY, MESSAGE);
|
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
|
unittest
|
||||||
{
|
{
|
||||||
import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
|
import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
|
||||||
import dscanner.analysis.helpers : assertAnalyzerWarnings;
|
import dscanner.analysis.helpers : assertAnalyzerWarningsDMD;
|
||||||
import std.format : format;
|
import std.format : format;
|
||||||
import std.stdio : stderr;
|
import std.stdio : stderr;
|
||||||
|
|
||||||
|
|
@ -76,11 +108,10 @@ unittest
|
||||||
sac.allman_braces_check = Check.enabled;
|
sac.allman_braces_check = Check.enabled;
|
||||||
|
|
||||||
// check common allman style violation
|
// check common allman style violation
|
||||||
assertAnalyzerWarnings(q{
|
assertAnalyzerWarningsDMD(`
|
||||||
void testAllman()
|
void testAllman()
|
||||||
{
|
{
|
||||||
while (true) { /+
|
while (true) { // [warn]: %s
|
||||||
^ [warn]: %s +/
|
|
||||||
auto f = 1;
|
auto f = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,7 +146,7 @@ unittest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}c.format(
|
`c.format(
|
||||||
AllManCheck.MESSAGE,
|
AllManCheck.MESSAGE,
|
||||||
AllManCheck.MESSAGE,
|
AllManCheck.MESSAGE,
|
||||||
AllManCheck.MESSAGE,
|
AllManCheck.MESSAGE,
|
||||||
|
|
@ -128,7 +159,7 @@ unittest
|
||||||
), sac);
|
), sac);
|
||||||
|
|
||||||
// check struct initialization
|
// check struct initialization
|
||||||
assertAnalyzerWarnings(q{
|
assertAnalyzerWarningsDMD(q{
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
struct Foo { int a; }
|
struct Foo { int a; }
|
||||||
|
|
@ -139,12 +170,11 @@ unittest
|
||||||
}, sac);
|
}, sac);
|
||||||
|
|
||||||
// allow duplicate braces
|
// allow duplicate braces
|
||||||
assertAnalyzerWarnings(q{
|
assertAnalyzerWarningsDMD(q{
|
||||||
unittest
|
unittest
|
||||||
{{
|
{{
|
||||||
}}
|
}}
|
||||||
}, sac);
|
}, sac);
|
||||||
|
|
||||||
|
|
||||||
stderr.writeln("Unittest for Allman passed.");
|
stderr.writeln("Unittest for Allman passed.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,6 @@ import dscanner.analysis.properly_documented_public_functions;
|
||||||
import dscanner.analysis.final_attribute;
|
import dscanner.analysis.final_attribute;
|
||||||
import dscanner.analysis.vcall_in_ctor;
|
import dscanner.analysis.vcall_in_ctor;
|
||||||
import dscanner.analysis.useless_initializer;
|
import dscanner.analysis.useless_initializer;
|
||||||
import dscanner.analysis.allman;
|
|
||||||
import dscanner.analysis.always_curly;
|
import dscanner.analysis.always_curly;
|
||||||
import dscanner.analysis.redundant_attributes;
|
import dscanner.analysis.redundant_attributes;
|
||||||
import dscanner.analysis.has_public_example;
|
import dscanner.analysis.has_public_example;
|
||||||
|
|
@ -668,10 +667,6 @@ BaseAnalyzer[] getAnalyzersForModuleAndConfig(string fileName,
|
||||||
checks ~= new UndocumentedDeclarationCheck(args.setSkipTests(
|
checks ~= new UndocumentedDeclarationCheck(args.setSkipTests(
|
||||||
analysisConfig.undocumented_declaration_check == Check.skipTests && !ut));
|
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))
|
if (moduleName.shouldRun!IfConstraintsIndentCheck(analysisConfig))
|
||||||
checks ~= new IfConstraintsIndentCheck(args.setSkipTests(
|
checks ~= new IfConstraintsIndentCheck(args.setSkipTests(
|
||||||
analysisConfig.if_constraints_indent == Check.skipTests && !ut));
|
analysisConfig.if_constraints_indent == Check.skipTests && !ut));
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ import dscanner.analysis.unused_variable : UnusedVariableCheck;
|
||||||
import dscanner.analysis.useless_assert : UselessAssertCheck;
|
import dscanner.analysis.useless_assert : UselessAssertCheck;
|
||||||
import dscanner.analysis.useless_initializer : UselessInitializerChecker;
|
import dscanner.analysis.useless_initializer : UselessInitializerChecker;
|
||||||
import dscanner.analysis.vcall_in_ctor : VcallCtorChecker;
|
import dscanner.analysis.vcall_in_ctor : VcallCtorChecker;
|
||||||
|
import dscanner.analysis.allman : AllManCheck;
|
||||||
|
|
||||||
version (unittest)
|
version (unittest)
|
||||||
enum ut = true;
|
enum ut = true;
|
||||||
|
|
@ -317,6 +318,12 @@ MessageSet analyzeDmd(string fileName, ASTCodegen.Module m, const char[] moduleN
|
||||||
fileName,
|
fileName,
|
||||||
config.vcall_in_ctor == Check.skipTests && !ut
|
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)
|
foreach (visitor; visitors)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue