Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
133 changes: 133 additions & 0 deletions src/analysis/allman.d
Original file line number Diff line number Diff line change
@@ -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.");
}
3 changes: 3 additions & 0 deletions src/analysis/config.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
5 changes: 5 additions & 0 deletions src/analysis/run.d
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand Down Expand Up @@ -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,
Expand Down