Add allman check (#446)

This commit is contained in:
Sebastian Wilzbach 2017-06-12 13:33:23 +02:00 committed by Basile Burg
parent dab25d5e31
commit 09205ddaf9
4 changed files with 142 additions and 0 deletions

View File

@ -129,6 +129,7 @@ Note that the "--skipTests" option is the equivalent of changing each
* Check for that imports are sorted. Initially implemented to lint Phobos. By default disabled.
* Virtual calls inside classes constructors.
* Useless initializers.
* Allman brace style
#### Wishlist

133
src/analysis/allman.d Normal file
View File

@ -0,0 +1,133 @@
// 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 analysis.allman;
import dparse.lexer;
import dparse.ast;
import 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)
{
auto curLine = tokens[i].line;
auto prevTokenLine = tokens[i-1].line;
if (tokens[i].type == tok!"{" && curLine == prevTokenLine)
{
// ignore struct initialization
if (tokens[i-1].type == tok!"=")
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 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 analysis.config : StaticAnalysisConfig, Check, disabledConfig;
import 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);
stderr.writeln("Unittest for Allman passed.");
}

View File

@ -179,4 +179,7 @@ struct StaticAnalysisConfig
@INI("Check for useless user defined initializers")
string useless_initializer = Check.enabled;
@INI("Check allman brace style")
string allman_braces_check = Check.disabled;
}

View File

@ -66,6 +66,7 @@ import analysis.properly_documented_public_functions;
import analysis.final_attribute;
import analysis.vcall_in_ctor;
import analysis.useless_initializer;
import analysis.allman;
import dsymbol.string_interning : internString;
import dsymbol.scope_;
@ -389,6 +390,10 @@ MessageSet analyze(string fileName, const Module m, const StaticAnalysisConfig a
checks ~= new UselessInitializerChecker(fileName,
analysisConfig.useless_initializer == Check.skipTests && !ut);
if (analysisConfig.allman_braces_check != Check.disabled)
checks ~= new AllManCheck(fileName, tokens,
analysisConfig.allman_braces_check == Check.skipTests && !ut);
version (none)
if (analysisConfig.redundant_if_check != Check.disabled)
checks ~= new IfStatementCheck(fileName, moduleScope,