Don't etag private/package by default
Declarations hidden from other packages (private or package protection) will not be tagged. New option --etagAll to tag private/package too.
This commit is contained in:
parent
5790fc3db0
commit
41b9ef708e
123
src/etags.d
123
src/etags.d
|
@ -16,13 +16,24 @@ import std.path;
|
||||||
import std.array;
|
import std.array;
|
||||||
import std.conv;
|
import std.conv;
|
||||||
|
|
||||||
|
// Prefix tags with their module name. Seems like correct behavior, but just
|
||||||
|
// in case, make it an option.
|
||||||
|
version = UseModuleContext;
|
||||||
|
|
||||||
|
// Could not find "official" definition of protection (public/private/etc).
|
||||||
|
// Behavior modeled here was reversed engineered based on dmd 2.067.
|
||||||
|
// class/interface and non-anonymous struct/union/enum members default to
|
||||||
|
// public, regardless of the enclosing declaration. template and anonymous
|
||||||
|
// struct/union/enum members default to the enclosing protection.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints ETAGS information to the given file.
|
* Prints ETAGS information to the given file.
|
||||||
* Params:
|
* Params:
|
||||||
* outpt = the file that ETAGS info is written to
|
* outpt = the file that ETAGS info is written to
|
||||||
|
* tagAll = if set, tag private/package declaration too
|
||||||
* fileNames = tags will be generated from these files
|
* fileNames = tags will be generated from these files
|
||||||
*/
|
*/
|
||||||
void printEtags(File output, string[] fileNames)
|
void printEtags(File output, bool tagAll, string[] fileNames)
|
||||||
{
|
{
|
||||||
LexerConfig config;
|
LexerConfig config;
|
||||||
StringCache cache = StringCache(StringCache.defaultBucketCount);
|
StringCache cache = StringCache(StringCache.defaultBucketCount);
|
||||||
|
@ -34,16 +45,17 @@ void printEtags(File output, string[] fileNames)
|
||||||
f.rawRead(bytes);
|
f.rawRead(bytes);
|
||||||
auto tokens = getTokensForParser(bytes, config, &cache);
|
auto tokens = getTokensForParser(bytes, config, &cache);
|
||||||
Module m = parseModule(tokens.array, fileName, null, &doNothing);
|
Module m = parseModule(tokens.array, fileName, null, &doNothing);
|
||||||
|
|
||||||
auto printer = new EtagsPrinter;
|
auto printer = new EtagsPrinter;
|
||||||
printer.moduleName = m.moduleFullName(fileName);
|
printer.moduleName = m.moduleFullName(fileName);
|
||||||
|
version(UseModuleContext)
|
||||||
// I think I like this
|
|
||||||
enum useModuleContext = true;
|
|
||||||
if (useModuleContext)
|
|
||||||
printer.context = printer.moduleName ~ ".";
|
printer.context = printer.moduleName ~ ".";
|
||||||
|
printer.privateVisibility = tagAll?
|
||||||
|
Visibility.exposed :
|
||||||
|
Visibility.hidden;
|
||||||
printer.bytes = bytes.sansBOM;
|
printer.bytes = bytes.sansBOM;
|
||||||
printer.visit(m);
|
printer.visit(m);
|
||||||
|
|
||||||
output.writef("\f\n%s,%u\n", fileName, printer.tags.length);
|
output.writef("\f\n%s,%u\n", fileName, printer.tags.length);
|
||||||
printer.tags.copy(output.lockingTextWriter);
|
printer.tags.copy(output.lockingTextWriter);
|
||||||
}
|
}
|
||||||
|
@ -51,6 +63,8 @@ void printEtags(File output, string[] fileNames)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
enum Visibility {exposed, hidden}
|
||||||
|
|
||||||
void doNothing(string, size_t, size_t, string, bool) {}
|
void doNothing(string, size_t, size_t, string, bool) {}
|
||||||
|
|
||||||
ubyte[] sansBOM(ubyte[] bytes)
|
ubyte[] sansBOM(ubyte[] bytes)
|
||||||
|
@ -59,7 +73,6 @@ ubyte[] sansBOM(ubyte[] bytes)
|
||||||
return (bytes.length >= 3 &&
|
return (bytes.length >= 3 &&
|
||||||
bytes[0] == 0xef && bytes[1] == 0xbb && bytes[2] == 0xbf)
|
bytes[0] == 0xef && bytes[1] == 0xbb && bytes[2] == 0xbf)
|
||||||
? bytes[3 .. $] : bytes;
|
? bytes[3 .. $] : bytes;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string moduleFullName(Module m, string fileName)
|
string moduleFullName(Module m, string fileName)
|
||||||
|
@ -72,7 +85,7 @@ string moduleFullName(Module m, string fileName)
|
||||||
return m.moduleDeclaration.moduleName.identifiers.map!(i=>i.text).join(".");
|
return m.moduleDeclaration.moduleName.identifiers.map!(i=>i.text).join(".");
|
||||||
}
|
}
|
||||||
|
|
||||||
class EtagsPrinter : ASTVisitor
|
final class EtagsPrinter : ASTVisitor
|
||||||
{
|
{
|
||||||
override void visit(const ModuleDeclaration dec)
|
override void visit(const ModuleDeclaration dec)
|
||||||
{
|
{
|
||||||
|
@ -84,9 +97,31 @@ class EtagsPrinter : ASTVisitor
|
||||||
dec.accept(this);
|
dec.accept(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override void visit(const Declaration dec)
|
||||||
|
{
|
||||||
|
// Update value of visibility based on this 'dec'.
|
||||||
|
if (dec.attributeDeclaration)
|
||||||
|
{
|
||||||
|
auto attr = dec.attributeDeclaration.attribute;
|
||||||
|
updateVisibility(attr.attribute.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// visibility needs to be restored to what it was when changed by
|
||||||
|
// attribute.
|
||||||
|
auto was = visibility;
|
||||||
|
foreach (attr; dec.attributes) {
|
||||||
|
updateVisibility(attr.attribute.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
dec.accept(this);
|
||||||
|
visibility = was;
|
||||||
|
}
|
||||||
|
|
||||||
override void visit(const ClassDeclaration dec)
|
override void visit(const ClassDeclaration dec)
|
||||||
{
|
{
|
||||||
maketag(dec.name);
|
maketag(dec.name);
|
||||||
|
// class members default to public
|
||||||
|
visibility = Visibility.exposed;
|
||||||
acceptInContext(dec, dec.name.text);
|
acceptInContext(dec, dec.name.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,12 +133,16 @@ class EtagsPrinter : ASTVisitor
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
maketag(dec.name);
|
maketag(dec.name);
|
||||||
|
// struct members default to public
|
||||||
|
visibility = Visibility.exposed;
|
||||||
acceptInContext(dec, dec.name.text);
|
acceptInContext(dec, dec.name.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const InterfaceDeclaration dec)
|
override void visit(const InterfaceDeclaration dec)
|
||||||
{
|
{
|
||||||
maketag(dec.name);
|
maketag(dec.name);
|
||||||
|
// interface members default to public
|
||||||
|
visibility = Visibility.exposed;
|
||||||
acceptInContext(dec, dec.name.text);
|
acceptInContext(dec, dec.name.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,36 +155,32 @@ class EtagsPrinter : ASTVisitor
|
||||||
override void visit(const FunctionDeclaration dec)
|
override void visit(const FunctionDeclaration dec)
|
||||||
{
|
{
|
||||||
maketag(dec.name);
|
maketag(dec.name);
|
||||||
bool was = inFunc;
|
// don't tag declarations in a function like thing
|
||||||
inFunc = true;
|
visibility = Visibility.hidden;
|
||||||
auto c = context;
|
|
||||||
acceptInContext(dec, dec.name.text);
|
acceptInContext(dec, dec.name.text);
|
||||||
inFunc = was;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const Constructor dec)
|
override void visit(const Constructor dec)
|
||||||
{
|
{
|
||||||
maketag("this", dec.location, dec.line);
|
maketag("this", dec.location, dec.line);
|
||||||
bool was = inFunc;
|
// don't tag declarations in a function like thing
|
||||||
inFunc = true;
|
visibility = Visibility.hidden;
|
||||||
auto c = context;
|
|
||||||
acceptInContext(dec, "this");
|
acceptInContext(dec, "this");
|
||||||
inFunc = was;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const Destructor dec)
|
override void visit(const Destructor dec)
|
||||||
{
|
{
|
||||||
maketag("~this", dec.index, dec.line);
|
maketag("~this", dec.index, dec.line);
|
||||||
bool was = inFunc;
|
// don't tag declarations in a function like thing
|
||||||
inFunc = true;
|
visibility = Visibility.hidden;
|
||||||
auto c = context;
|
|
||||||
acceptInContext(dec, "~this");
|
acceptInContext(dec, "~this");
|
||||||
inFunc = was;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const EnumDeclaration dec)
|
override void visit(const EnumDeclaration dec)
|
||||||
{
|
{
|
||||||
maketag(dec.name);
|
maketag(dec.name);
|
||||||
|
// enum members default to public
|
||||||
|
visibility = Visibility.exposed;
|
||||||
acceptInContext(dec, dec.name.text);
|
acceptInContext(dec, dec.name.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,6 +192,8 @@ class EtagsPrinter : ASTVisitor
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
maketag(dec.name);
|
maketag(dec.name);
|
||||||
|
// union members default to public
|
||||||
|
visibility = Visibility.exposed;
|
||||||
acceptInContext(dec, dec.name.text);
|
acceptInContext(dec, dec.name.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +214,7 @@ class EtagsPrinter : ASTVisitor
|
||||||
dec.accept(this);
|
dec.accept(this);
|
||||||
inUnittest = was;
|
inUnittest = was;
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const VariableDeclaration dec)
|
override void visit(const VariableDeclaration dec)
|
||||||
{
|
{
|
||||||
foreach (d; dec.declarators)
|
foreach (d; dec.declarators)
|
||||||
|
@ -218,15 +255,35 @@ class EtagsPrinter : ASTVisitor
|
||||||
maketag("invariant", dec.index, dec.line);
|
maketag("invariant", dec.index, dec.line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void acceptInContext(Dec)(Dec dec, string name)
|
private:
|
||||||
|
void updateVisibility(IdType type) {
|
||||||
|
// maybe change visibility based on attribute 'type'
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case tok!"export":
|
||||||
|
case tok!"public":
|
||||||
|
case tok!"protected":
|
||||||
|
visibility = Visibility.exposed;
|
||||||
|
break;
|
||||||
|
case tok!"package":
|
||||||
|
case tok!"private":
|
||||||
|
visibility = privateVisibility;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// no change
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void acceptInContext(const ASTNode dec, string name)
|
||||||
{
|
{
|
||||||
// nest context before journeying on
|
// nest context before journeying on
|
||||||
auto c = context;
|
auto c = context;
|
||||||
context ~= name ~ ".";
|
context ~= name ~ ".";
|
||||||
dec.accept(this);
|
dec.accept(this);
|
||||||
context = c;
|
context = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void maketag(Token name)
|
void maketag(Token name)
|
||||||
{
|
{
|
||||||
maketag(name.text, name.index, name.line);
|
maketag(name.text, name.index, name.line);
|
||||||
|
@ -234,8 +291,8 @@ class EtagsPrinter : ASTVisitor
|
||||||
|
|
||||||
void maketag(string text, size_t index, ulong line)
|
void maketag(string text, size_t index, ulong line)
|
||||||
{
|
{
|
||||||
// skip declaration in unittests and funcs
|
// skip unittests and hidden declarations
|
||||||
if (inUnittest || inFunc) return;
|
if (inUnittest || visibility == Visibility.hidden) return;
|
||||||
|
|
||||||
// tag is a searchable string from beginning of line
|
// tag is a searchable string from beginning of line
|
||||||
size_t b = index;
|
size_t b = index;
|
||||||
|
@ -255,14 +312,20 @@ class EtagsPrinter : ASTVisitor
|
||||||
line,
|
line,
|
||||||
b);
|
b);
|
||||||
}
|
}
|
||||||
|
|
||||||
alias visit = ASTVisitor.visit;
|
alias visit = ASTVisitor.visit;
|
||||||
|
|
||||||
|
// state
|
||||||
|
// visibility of declarations (i.e. should we tag)
|
||||||
|
Visibility visibility = Visibility.exposed;
|
||||||
bool inUnittest;
|
bool inUnittest;
|
||||||
bool inFunc;
|
|
||||||
|
// inputs
|
||||||
ubyte[] bytes;
|
ubyte[] bytes;
|
||||||
string moduleName;
|
string moduleName;
|
||||||
string tags;
|
|
||||||
string context;
|
string context;
|
||||||
}
|
Visibility privateVisibility = Visibility.hidden;
|
||||||
|
|
||||||
|
// ouput
|
||||||
|
string tags;
|
||||||
|
}
|
||||||
|
|
14
src/main.d
14
src/main.d
|
@ -49,6 +49,7 @@ int run(string[] args)
|
||||||
bool highlight;
|
bool highlight;
|
||||||
bool ctags;
|
bool ctags;
|
||||||
bool etags;
|
bool etags;
|
||||||
|
bool etagsAll;
|
||||||
bool help;
|
bool help;
|
||||||
bool tokenCount;
|
bool tokenCount;
|
||||||
bool syntaxCheck;
|
bool syntaxCheck;
|
||||||
|
@ -69,7 +70,7 @@ int run(string[] args)
|
||||||
{
|
{
|
||||||
getopt(args, std.getopt.config.caseSensitive, "sloc|l", &sloc,
|
getopt(args, std.getopt.config.caseSensitive, "sloc|l", &sloc,
|
||||||
"highlight", &highlight, "ctags|c", &ctags, "help|h", &help,
|
"highlight", &highlight, "ctags|c", &ctags, "help|h", &help,
|
||||||
"etags|e", &etags,
|
"etags|e", &etags, "etagsAll", &etagsAll,
|
||||||
"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, "styleCheck|S", &styleCheck,
|
"tokenDump", &tokenDump, "styleCheck|S", &styleCheck,
|
||||||
|
@ -120,9 +121,9 @@ int run(string[] args)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto optionCount = count!"a"([sloc, highlight, ctags, etags, tokenCount,
|
auto optionCount = count!"a"([sloc, highlight, ctags, tokenCount,
|
||||||
syntaxCheck, ast, imports, outline, tokenDump, styleCheck, defaultConfig,
|
syntaxCheck, ast, imports, outline, tokenDump, styleCheck, defaultConfig,
|
||||||
report, symbolName !is null]);
|
report, symbolName !is null, etags, etagsAll]);
|
||||||
if (optionCount > 1)
|
if (optionCount > 1)
|
||||||
{
|
{
|
||||||
stderr.writeln("Too many options specified");
|
stderr.writeln("Too many options specified");
|
||||||
|
@ -177,9 +178,9 @@ int run(string[] args)
|
||||||
{
|
{
|
||||||
stdout.printCtags(expandArgs(args));
|
stdout.printCtags(expandArgs(args));
|
||||||
}
|
}
|
||||||
else if (etags)
|
else if (etags || etagsAll)
|
||||||
{
|
{
|
||||||
stdout.printEtags(expandArgs(args));
|
stdout.printEtags(etagsAll, expandArgs(args));
|
||||||
}
|
}
|
||||||
else if (styleCheck)
|
else if (styleCheck)
|
||||||
{
|
{
|
||||||
|
@ -369,6 +370,9 @@ options:
|
||||||
etags information requires a filename, so stdin cannot be used in place
|
etags information requires a filename, so stdin cannot be used in place
|
||||||
of a filename.
|
of a filename.
|
||||||
|
|
||||||
|
--etagsAll sourceFile
|
||||||
|
Same as --etags except private and package declarations are tagged too.
|
||||||
|
|
||||||
--ast | --xml sourceFile
|
--ast | --xml sourceFile
|
||||||
Generates an XML representation of the source files abstract syntax
|
Generates an XML representation of the source files abstract syntax
|
||||||
tree. If no files are specified, input is read from stdin.
|
tree. If no files are specified, input is read from stdin.
|
||||||
|
|
Loading…
Reference in New Issue