Added basic style checker
This commit is contained in:
parent
070f9ac83b
commit
22ca0cd284
1
build.sh
1
build.sh
|
@ -8,6 +8,7 @@ dmd\
|
||||||
astprinter.d\
|
astprinter.d\
|
||||||
formatter.d\
|
formatter.d\
|
||||||
outliner.d\
|
outliner.d\
|
||||||
|
style.d\
|
||||||
stdx/*.d\
|
stdx/*.d\
|
||||||
stdx/d/*.d\
|
stdx/d/*.d\
|
||||||
datapicked/dpick/buffer/*.d\
|
datapicked/dpick/buffer/*.d\
|
||||||
|
|
15
main.d
15
main.d
|
@ -25,6 +25,7 @@ import ctags;
|
||||||
import astprinter;
|
import astprinter;
|
||||||
import imports;
|
import imports;
|
||||||
import outliner;
|
import outliner;
|
||||||
|
import style;
|
||||||
|
|
||||||
int main(string[] args)
|
int main(string[] args)
|
||||||
{
|
{
|
||||||
|
@ -41,6 +42,7 @@ int main(string[] args)
|
||||||
bool muffin;
|
bool muffin;
|
||||||
bool outline;
|
bool outline;
|
||||||
bool tokenDump;
|
bool tokenDump;
|
||||||
|
bool styleCheck;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -48,7 +50,8 @@ int main(string[] args)
|
||||||
"ctags|c", &ctags, "recursive|r|R", &recursive, "help|h", &help,
|
"ctags|c", &ctags, "recursive|r|R", &recursive, "help|h", &help,
|
||||||
"tokenCount|t", &tokenCount, "syntaxCheck|s", &syntaxCheck,
|
"tokenCount|t", &tokenCount, "syntaxCheck|s", &syntaxCheck,
|
||||||
"ast|xml", &ast, "imports|i", &imports, "outline|o", &outline,
|
"ast|xml", &ast, "imports|i", &imports, "outline|o", &outline,
|
||||||
"tokenDump", &tokenDump, "muffinButton", &muffin);
|
"tokenDump", &tokenDump, "styleCheck", &styleCheck,
|
||||||
|
"muffinButton", &muffin);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -77,7 +80,7 @@ int main(string[] args)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto optionCount = count!"a"([sloc, highlight, ctags, tokenCount,
|
auto optionCount = count!"a"([sloc, highlight, ctags, tokenCount,
|
||||||
syntaxCheck, ast, imports, outline, tokenDump]);
|
syntaxCheck, ast, imports, outline, tokenDump, styleCheck]);
|
||||||
if (optionCount > 1)
|
if (optionCount > 1)
|
||||||
{
|
{
|
||||||
stderr.writeln("Too many options specified");
|
stderr.writeln("Too many options specified");
|
||||||
|
@ -112,6 +115,10 @@ int main(string[] args)
|
||||||
{
|
{
|
||||||
stdout.printCtags(expandArgs(args, recursive));
|
stdout.printCtags(expandArgs(args, recursive));
|
||||||
}
|
}
|
||||||
|
else if (styleCheck)
|
||||||
|
{
|
||||||
|
stdout.styleCheck(expandArgs(args, recursive));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool usingStdin = args.length == 1;
|
bool usingStdin = args.length == 1;
|
||||||
|
@ -251,6 +258,10 @@ options:
|
||||||
syntax errors to stdout. One error or warning is printed per line.
|
syntax errors to stdout. One error or warning is printed per line.
|
||||||
If no files are specified, input is read from stdin.
|
If no files are specified, input is read from stdin.
|
||||||
|
|
||||||
|
--styleCheck [sourceFiles]
|
||||||
|
Lexes and parses sourceFiles, printing the line and column number of any
|
||||||
|
style guideline violations to stdout.
|
||||||
|
|
||||||
--ctags | -c sourceFile
|
--ctags | -c sourceFile
|
||||||
Generates ctags information from the given source code file. Note that
|
Generates ctags information from the given source code file. Note that
|
||||||
ctags information requires a filename, so stdin cannot be used in place
|
ctags information requires a filename, so stdin cannot be used in place
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
// Copyright Brian Schott (Sir Alaran) 2014.
|
||||||
|
// 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 style;
|
||||||
|
|
||||||
|
import stdx.d.ast;
|
||||||
|
import stdx.d.lexer;
|
||||||
|
import stdx.d.parser;
|
||||||
|
import std.stdio;
|
||||||
|
import std.regex;
|
||||||
|
import std.array;
|
||||||
|
import std.conv;
|
||||||
|
|
||||||
|
void doNothing(string, size_t, size_t, string) {}
|
||||||
|
|
||||||
|
void styleCheck(File output, string[] fileNames)
|
||||||
|
{
|
||||||
|
foreach (fileName; fileNames)
|
||||||
|
{
|
||||||
|
File f = File(fileName);
|
||||||
|
auto bytes = uninitializedArray!(ubyte[])(to!size_t(f.size));
|
||||||
|
f.rawRead(bytes);
|
||||||
|
auto tokens = byToken(bytes);
|
||||||
|
Module m = parseModule(tokens.array, fileName, &doNothing);
|
||||||
|
auto checker = new StyleChecker;
|
||||||
|
checker.fileName = fileName;
|
||||||
|
checker.visit(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StyleChecker : ASTVisitor
|
||||||
|
{
|
||||||
|
enum varFunNameRegex = `^([\p{Ll}_][_\w\d]*|[\p{Lu}_]+)$`;
|
||||||
|
enum aggregateNameRegex = `^\p{Lu}[\w\d]*$`;
|
||||||
|
enum moduleNameRegex = `^\p{Ll}+$`;
|
||||||
|
|
||||||
|
override void visit(ModuleDeclaration dec)
|
||||||
|
{
|
||||||
|
foreach (part; dec.moduleName.identifiers)
|
||||||
|
{
|
||||||
|
if (part.text.matchFirst(moduleNameRegex).length == 0)
|
||||||
|
writeln(fileName, "(", part.line, ":", part.column, ") ",
|
||||||
|
"Module/package name ", part.text, " does not match style guidelines");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(Declarator dec)
|
||||||
|
{
|
||||||
|
checkLowercaseName("Variable", dec.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(FunctionDeclaration dec)
|
||||||
|
{
|
||||||
|
checkLowercaseName("Function", dec.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkLowercaseName(string type, ref Token name)
|
||||||
|
{
|
||||||
|
if (name.text.matchFirst(varFunNameRegex).length == 0)
|
||||||
|
writeln(fileName, "(", name.line, ":", name.column, ") ",
|
||||||
|
type, " name ", name.text, " does not match style guidelines");
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(ClassDeclaration dec)
|
||||||
|
{
|
||||||
|
checkAggregateName("Class", dec.name);
|
||||||
|
dec.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(EnumDeclaration dec)
|
||||||
|
{
|
||||||
|
if (dec.name.text is null || dec.name.text.length == 0)
|
||||||
|
return;
|
||||||
|
checkAggregateName("Enum", dec.name);
|
||||||
|
dec.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(StructDeclaration dec)
|
||||||
|
{
|
||||||
|
checkAggregateName("Struct", dec.name);
|
||||||
|
dec.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkAggregateName(string aggregateType, ref Token name)
|
||||||
|
{
|
||||||
|
if (name.text.matchFirst(aggregateNameRegex).length == 0)
|
||||||
|
writeln(fileName, "(", name.line, ":", name.column, ") ",
|
||||||
|
aggregateType, " name ", name.text,
|
||||||
|
" does not match style guidelines");
|
||||||
|
}
|
||||||
|
|
||||||
|
alias ASTVisitor.visit visit;
|
||||||
|
string fileName;
|
||||||
|
}
|
Loading…
Reference in New Issue