1 /** 2 Copyright: Copyright (c) 2020, 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 Extensions to the visitor in `libclang_ast.ast`. 11 12 Intende to move this code to clang_extensions if this approach to extending the 13 clang AST works well. 14 */ 15 module dextool.plugin.mutate.backend.analyze.extensions; 16 17 import clang.Cursor : Cursor; 18 import libclang_ast.ast : Visitor; 19 20 import my.set; 21 22 static import dextool.clang_extensions; 23 24 static import libclang_ast.ast; 25 26 /** 27 * the ignoreCursors solution is not particularly principaled. It is an ugly hack that should be moved to the core AST `Visitor` and thus completely h 28 */ 29 class ExtendedVisitor : Visitor { 30 import libclang_ast.ast; 31 import dextool.clang_extensions; 32 33 alias visit = Visitor.visit; 34 35 // A cursors that has been decorated as one of the extended should be 36 // "ignored" if it is found "again". Which happens for e.g. a 37 // BinaryOperator inside a if-statement. It will first occur as a 38 // IfStmtCond and then a BinaryOperator. 39 Set!size_t ignoreCursors; 40 41 void visit(const(IfStmtInit) value) { 42 visit(cast(const(Statement)) value); 43 } 44 45 void visit(const(IfStmtCond) value) { 46 visit(cast(const(Expression)) value); 47 } 48 49 void visit(const(IfStmtThen) value) { 50 visit(cast(const(Statement)) value); 51 } 52 53 void visit(const(IfStmtElse) value) { 54 visit(cast(const(Statement)) value); 55 } 56 } 57 58 // using dispatch because the wrapped cursor has to be re-visited as its 59 // original `type`. Not just the colored `IfStmt` node. 60 61 final class IfStmtInit : libclang_ast.ast.Statement { 62 this(Cursor cursor) @safe { 63 super(cursor); 64 } 65 66 void accept(ExtendedVisitor v) @safe const { 67 static import libclang_ast.ast; 68 69 libclang_ast.ast.dispatch(cursor, v); 70 } 71 } 72 73 final class IfStmtCond : libclang_ast.ast.Expression { 74 this(Cursor cursor) @safe { 75 super(cursor); 76 } 77 78 void accept(ExtendedVisitor v) @safe const { 79 static import libclang_ast.ast; 80 81 libclang_ast.ast.dispatch(cursor, v); 82 } 83 } 84 85 final class IfStmtThen : libclang_ast.ast.Statement { 86 this(Cursor cursor) @safe { 87 super(cursor); 88 } 89 90 void accept(ExtendedVisitor v) @safe const { 91 static import libclang_ast.ast; 92 93 libclang_ast.ast.dispatch(cursor, v); 94 } 95 } 96 97 final class IfStmtElse : libclang_ast.ast.Statement { 98 this(Cursor cursor) @safe { 99 super(cursor); 100 } 101 102 void accept(ExtendedVisitor v) @safe const { 103 static import libclang_ast.ast; 104 105 libclang_ast.ast.dispatch(cursor, v); 106 } 107 } 108 109 void accept(T)(const(libclang_ast.ast.IfStmt) n, T v) if (is(T : ExtendedVisitor)) { 110 import dextool.clang_extensions; 111 112 auto stmt = getIfStmt(n.cursor); 113 accept(stmt, v); 114 } 115 116 void accept(T)(ref dextool.clang_extensions.IfStmt n, T v) 117 if (is(T : ExtendedVisitor)) { 118 import std.traits : hasMember; 119 120 static if (hasMember!(T, "incr")) 121 v.incr; 122 123 if (n.init_.isValid) { 124 auto sub = new IfStmtInit(n.init_); 125 static if (__traits(hasMember, T, "ignoreCursors")) { 126 v.ignoreCursors.add(n.init_.toHash); 127 } 128 v.visit(sub); 129 } 130 if (n.cond.isValid) { 131 auto sub = new IfStmtCond(n.cond); 132 static if (__traits(hasMember, T, "ignoreCursors")) { 133 v.ignoreCursors.add(n.cond.toHash); 134 } 135 v.visit(sub); 136 } 137 if (n.then.isValid) { 138 auto sub = new IfStmtThen(n.then); 139 v.visit(sub); 140 } 141 if (n.else_.isValid) { 142 auto sub = new IfStmtElse(n.else_); 143 v.visit(sub); 144 } 145 146 static if (hasMember!(T, "decr")) 147 v.decr; 148 }