1 /**
2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved.
3 License: MPL-2
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 This Source Code Form is subject to the terms of the Mozilla Public License,
7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain
8 one at http://mozilla.org/MPL/2.0/.
9 */
10 module dextool.plugin.analyze.visitor;
11 
12 import libclang_ast.ast : Visitor;
13 import dextool.type : AbsolutePath;
14 
15 @safe:
16 
17 /** Calculate McCabe per file and function.
18 */
19 final class TUVisitor : Visitor {
20     import std..string : startsWith;
21     import dsrcgen.cpp;
22     import libclang_ast.ast;
23     import libclang_ast.cursor_logger : logNode, mixinNodeLog;
24     import cpptooling.data.symbol : Container;
25 
26     alias visit = Visitor.visit;
27 
28     mixin generateIndentIncrDecr;
29 
30     alias CallbackT(T) = void delegate(const(T) v) @safe;
31 
32     private static string makeCallback(string kind) {
33         string s;
34         string alias_name = "On" ~ kind ~ "T";
35         s = "alias " ~ alias_name ~ " = CallbackT!" ~ kind ~ ";\n";
36         s ~= alias_name ~ "[] on" ~ kind ~ ";\n";
37         return s;
38     }
39 
40     private static string makeCallbacks(Kinds...)() {
41         string s;
42         foreach (k; Kinds)
43             s ~= makeCallback(k.stringof);
44         return s;
45     }
46 
47     // note that it requires a member variable called restrict
48     private static string makeVisitor(string node_t, string callback_member) {
49         string s = "override void visit(scope const " ~ node_t ~ " v) @trusted {\n";
50         s ~= "auto callbacks = " ~ callback_member ~ ";";
51         s ~= q{
52             if (!v.cursor.location.path.startsWith(restrict.toString))
53                 return;
54             foreach (c; callbacks)
55                 c(v);
56             v.accept(this);
57         };
58 
59         s ~= "}\n";
60         return s;
61     }
62 
63     private static string makeVisitors(Kinds...)() {
64         string s;
65         foreach (k; Kinds) {
66             s ~= makeVisitor(k.stringof, "on" ~ k.stringof);
67         }
68         return s;
69     }
70 
71     import std.meta : AliasSeq;
72 
73     private alias callbackKinds = AliasSeq!(FunctionDecl, Constructor,
74             Destructor, CxxMethod, ConversionFunction, FunctionTemplate, ClassTemplate);
75 
76     // debugging
77     //pragma(msg, makeCallbacks!callbackKinds);
78     //pragma(msg, makeVisitors!callbackKinds);
79 
80     mixin(makeCallbacks!(callbackKinds));
81     mixin(makeVisitors!(callbackKinds));
82 
83     private AbsolutePath restrict;
84 
85     /**
86      * Params:
87      *  restrict = only analyze files starting with this path
88      */
89     this(AbsolutePath restrict) nothrow {
90         this.restrict = restrict;
91     }
92 
93     override void visit(scope const(TranslationUnit) v) {
94         v.accept(this);
95     }
96 
97     override void visit(scope const(Attribute) v) {
98         v.accept(this);
99     }
100 
101     override void visit(scope const(Declaration) v) {
102         v.accept(this);
103     }
104 
105     override void visit(scope const(Directive) v) {
106         v.accept(this);
107     }
108 
109     override void visit(scope const(Expression) v) {
110         v.accept(this);
111     }
112 
113     override void visit(scope const(Preprocessor) v) {
114         v.accept(this);
115     }
116 
117     override void visit(scope const(Reference) v) {
118         v.accept(this);
119     }
120 
121     override void visit(scope const(Statement) v) {
122         v.accept(this);
123     }
124 }