Add allman check (#446)
This commit is contained in:
parent
dab25d5e31
commit
09205ddaf9
|
@ -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.
|
* Check for that imports are sorted. Initially implemented to lint Phobos. By default disabled.
|
||||||
* Virtual calls inside classes constructors.
|
* Virtual calls inside classes constructors.
|
||||||
* Useless initializers.
|
* Useless initializers.
|
||||||
|
* Allman brace style
|
||||||
|
|
||||||
#### Wishlist
|
#### Wishlist
|
||||||
|
|
||||||
|
|
|
@ -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.");
|
||||||
|
}
|
|
@ -179,4 +179,7 @@ struct StaticAnalysisConfig
|
||||||
|
|
||||||
@INI("Check for useless user defined initializers")
|
@INI("Check for useless user defined initializers")
|
||||||
string useless_initializer = Check.enabled;
|
string useless_initializer = Check.enabled;
|
||||||
|
|
||||||
|
@INI("Check allman brace style")
|
||||||
|
string allman_braces_check = Check.disabled;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ import analysis.properly_documented_public_functions;
|
||||||
import analysis.final_attribute;
|
import analysis.final_attribute;
|
||||||
import analysis.vcall_in_ctor;
|
import analysis.vcall_in_ctor;
|
||||||
import analysis.useless_initializer;
|
import analysis.useless_initializer;
|
||||||
|
import analysis.allman;
|
||||||
|
|
||||||
import dsymbol.string_interning : internString;
|
import dsymbol.string_interning : internString;
|
||||||
import dsymbol.scope_;
|
import dsymbol.scope_;
|
||||||
|
@ -389,6 +390,10 @@ MessageSet analyze(string fileName, const Module m, const StaticAnalysisConfig a
|
||||||
checks ~= new UselessInitializerChecker(fileName,
|
checks ~= new UselessInitializerChecker(fileName,
|
||||||
analysisConfig.useless_initializer == Check.skipTests && !ut);
|
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)
|
version (none)
|
||||||
if (analysisConfig.redundant_if_check != Check.disabled)
|
if (analysisConfig.redundant_if_check != Check.disabled)
|
||||||
checks ~= new IfStatementCheck(fileName, moduleScope,
|
checks ~= new IfStatementCheck(fileName, moduleScope,
|
||||||
|
|
Loading…
Reference in New Issue