1 //Counts D features, doesn't really work yet :<(
2 module commands.featurecount;
3 
4 import std;
5 import util.debug_;
6 import util.statman;
7 
8 //The Kitchen sink
9 import dmd.astbase;
10 import dmd.errors;
11 import dmd.parse;
12 import dmd.transitivevisitor;
13 import dmd.dmodule;
14 import dmd.func;
15 import dmd.globals;
16 import dmd.id;
17 import dmd.identifier;
18 import dmd.visitor;
19 import dmd.frontend;
20 import dmd.dmangle;
21 import dmd.dsymbol;
22 import dmd.declaration;
23 import dmd.dtemplate;
24 ///Stolen from J.C.'s thing in github/dmd, gets the default dmd import paths on a system
25 string[] defaultImportPaths(string dlangDir)
26 {
27     import std.path : buildNormalizedPath, buildPath, dirName;
28     import std.process : environment;
29 
30     const druntimeDir = dlangDir.buildPath("druntime", "import");
31     const phobosDir = dlangDir.buildPath("phobos");
32 
33     return [environment.get("DRUNTIME_PATH", druntimeDir),
34         environment.get("PHOBOS_PATH", phobosDir)];
35 }
36 
37 ///Sorry god, utility function because dmd works in terms of c strings due to extern(C++) limitations
38 string cToD(inout char* x)
39 {
40     import core.stdc..string : strlen;
41 
42     return cast(immutable char[]) x[0 .. x.strlen];
43 }
44 ///Walks the semantic time AST, parse time is apparently not enough (e.g. needs sema to have everything)
45 extern (C++) //This is annoying but required unfortunately 
46 class FeatureCountVisitor : SemanticTimePermissiveVisitor
47 {
48     alias visit = SemanticTimePermissiveVisitor.visit;
49     StatManager stats;
50     this()
51     {
52         stats = StatManager("FeatureCountVisitor");
53     }
54 
55     override void visit(Module mod)
56     {
57         foreach (x; *mod.members)
58         {
59             x.accept(this);
60         }
61 
62     }
63 
64     override void visit(Dsymbol sym)
65     {
66         
67         debug writeln("stub dsymbol");
68     }
69 
70     override void visit(TemplateDeclaration decl)
71     {
72         
73         if(auto c = decl.constraint)
74         {
75             import core.stdc.stdio;
76             
77         }
78     }
79     override void visit(FuncDeclaration func)
80     {
81         import std.conv : to;
82 
83         auto tmp = stats.category("functions").category(func.mangleExact.cToD);
84         with (tmp)
85         {
86             setAtom("fullSignature", func.toFullSignature.cToD);
87             setAtom("ProtectionClass", func.prot.to!string);
88             with (category("loc"))
89             {
90                 setAtom("filename", func.loc.filename.cToD);
91                 setAtom("line", func.loc.linnum);
92             }
93         }
94 
95     }
96 }
97 
98 auto command(string[] args)
99 {
100     import std.getopt : getopt, config;
101     import std.file : readText;
102     initDMD;
103     scope (exit)
104         deinitializeDMD;
105 
106     string dimport;
107     string fileName;
108     string content;
109 
110 
111     auto parseResult = getopt(args, config.required, "I|import", &dimport, "f|file", &fileName);
112 
113     if(fileName != "") {
114         content = readText(fileName);
115     } else {
116         //stdin
117     }
118         
119     defaultImportPaths(dimport).each!writeln;
120     defaultImportPaths(dimport).each!addImport;
121     //Just dump any issues to stderr
122     scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated);
123     scope mod = parseModule(fileName, content, diagnosticReporter);
124 
125     scope tmp = new FeatureCountVisitor();
126 
127     //We wamt the whole shebang 
128     mod.module_.fullSemantic;
129 
130     mod.module_.accept(tmp);
131     
132     return tmp.stats.gcDup;
133 }