148 lines
3.2 KiB
D
148 lines
3.2 KiB
D
// Distributed under the Boost Software License, Version 1.0.
|
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
module dscanner.analysis.allman;
|
|
|
|
import dparse.lexer;
|
|
import dparse.ast;
|
|
import dscanner.analysis.base : BaseAnalyzer;
|
|
import dsymbol.scope_ : Scope;
|
|
|
|
import std.algorithm;
|
|
import std.range;
|
|
|
|
/**
|
|
Checks for the allman style (braces should be on their own line)
|
|
------------
|
|
if (param < 0) {
|
|
}
|
|
------------
|
|
should be
|
|
------------
|
|
if (param < 0)
|
|
{
|
|
}
|
|
------------
|
|
*/
|
|
class AllManCheck : BaseAnalyzer
|
|
{
|
|
///
|
|
this(string fileName, const(Token)[] tokens, bool skipTests = false)
|
|
{
|
|
super(fileName, null, skipTests);
|
|
foreach (i; 1 .. tokens.length - 1)
|
|
{
|
|
const curLine = tokens[i].line;
|
|
const prevTokenLine = tokens[i-1].line;
|
|
if (tokens[i].type == tok!"{" && curLine == prevTokenLine)
|
|
{
|
|
// ignore struct initialization
|
|
if (tokens[i-1].type == tok!"=")
|
|
continue;
|
|
// ignore duplicate braces
|
|
if (tokens[i-1].type == tok!"{" && tokens[i - 2].line != curLine)
|
|
continue;
|
|
// ignore inline { } braces
|
|
if (curLine != tokens[i + 1].line)
|
|
addErrorMessage(tokens[i].line, tokens[i].column, KEY, MESSAGE);
|
|
}
|
|
if (tokens[i].type == tok!"}" && curLine == prevTokenLine)
|
|
{
|
|
// ignore duplicate braces
|
|
if (tokens[i-1].type == tok!"}" && tokens[i - 2].line != curLine)
|
|
continue;
|
|
// ignore inline { } braces
|
|
if (!tokens[0 .. i].retro.until!(t => t.line != curLine).canFind!(t => t.type == tok!"{"))
|
|
addErrorMessage(tokens[i].line, tokens[i].column, 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 std.format : format;
|
|
import std.stdio : stderr;
|
|
|
|
StaticAnalysisConfig sac = disabledConfig();
|
|
sac.allman_braces_check = Check.enabled;
|
|
|
|
// check common allman style violation
|
|
assertAnalyzerWarnings(q{
|
|
void testAllman()
|
|
{
|
|
while (true) { // [warn]: %s
|
|
auto f = 1;
|
|
}
|
|
|
|
do { // [warn]: %s
|
|
auto f = 1;
|
|
} while (true);
|
|
|
|
// inline braces are OK
|
|
while (true) { auto f = 1; }
|
|
|
|
if (true) { // [warn]: %s
|
|
auto f = 1;
|
|
}
|
|
if (true)
|
|
{
|
|
auto f = 1; } // [warn]: %s
|
|
if (true) { auto f = 1; }
|
|
foreach (r; [1]) { // [warn]: %s
|
|
}
|
|
foreach (r; [1]) { }
|
|
foreach_reverse (r; [1]) { // [warn]: %s
|
|
}
|
|
foreach_reverse (r; [1]) { }
|
|
for (int i = 0; i < 10; i++) { // [warn]: %s
|
|
}
|
|
for (int i = 0; i < 10; i++) { }
|
|
|
|
// nested check
|
|
while (true) { // [warn]: %s
|
|
while (true) { // [warn]: %s
|
|
auto f = 1;
|
|
}
|
|
}
|
|
}
|
|
}c.format(
|
|
AllManCheck.MESSAGE,
|
|
AllManCheck.MESSAGE,
|
|
AllManCheck.MESSAGE,
|
|
AllManCheck.MESSAGE,
|
|
AllManCheck.MESSAGE,
|
|
AllManCheck.MESSAGE,
|
|
AllManCheck.MESSAGE,
|
|
AllManCheck.MESSAGE,
|
|
AllManCheck.MESSAGE,
|
|
), sac);
|
|
|
|
// check struct initialization
|
|
assertAnalyzerWarnings(q{
|
|
unittest
|
|
{
|
|
struct Foo { int a; }
|
|
Foo foo = {
|
|
a: 1;
|
|
};
|
|
}
|
|
}, sac);
|
|
|
|
// allow duplicate braces
|
|
assertAnalyzerWarnings(q{
|
|
unittest
|
|
{{
|
|
}}
|
|
}, sac);
|
|
|
|
|
|
stderr.writeln("Unittest for Allman passed.");
|
|
}
|