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 }