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.fuzzer.backend.generate_xml; 11 12 import std.conv : to; 13 14 import logger = std.experimental.logger; 15 16 import cpptooling.data : CppRoot, CFunction, USRType, CxParam, CppVariable; 17 18 import dextool.compilation_db : CompileCommandFilter; 19 20 import dextool.plugin.fuzzer.type : Param, Symbol; 21 import dextool.plugin.fuzzer.backend.type; 22 import dextool.plugin.fuzzer.backend.unique_sequence : Sequence; 23 24 /// TODO change to @safe when the base compiler is upgraded to 2.074+ 25 void generateConfigCompilerFilter(ref CompileCommandFilter compiler_flag_filter, 26 ref TemplateConfig tmpl_conf) @trusted { 27 import std.conv : to; 28 import std.xml; 29 30 auto compiler_tag = new Element("compiler_flag_filter"); 31 compiler_tag.tag.attr["skip_compiler_args"] = compiler_flag_filter 32 .skipCompilerArgs.to!string(); 33 foreach (value; compiler_flag_filter.filter) { 34 auto tag = new Element("exclude"); 35 tag ~= new Text(value); 36 compiler_tag ~= tag; 37 } 38 39 tmpl_conf.doc ~= compiler_tag; 40 } 41 42 /// TODO change to @safe when the base compiler is upgraded to 2.074+ 43 void generateConfigPerFunction(ref ImplData impl, ref TemplateConfig tmpl_conf) @trusted { 44 import std.xml; 45 import cpptooling.data.symbol.types : FullyQualifiedNameType; 46 47 // no duplications are allowed 48 bool[FullyQualifiedNameType] generated_syms; 49 50 // dump the user excluded symbols 51 foreach (s; impl.excludedSymbols) { 52 auto sym = tmpl_conf.makeSymbol; 53 sym.tag.attr["name"] = cast(FullyQualifiedNameType) s; 54 sym.tag.attr["filter"] = "exclude"; 55 generated_syms[s] = true; 56 } 57 58 foreach (f; impl.root.funcRange) { 59 if (auto s = FullyQualifiedNameType(f.name) in generated_syms) { 60 continue; 61 } 62 63 auto sym = tmpl_conf.makeSymbol; 64 65 if (auto s = FullyQualifiedNameType(f.name) in impl.symbols) { 66 generateConfigForFunctionValidityFromUser(f, *s, sym); 67 } else { 68 generateConfigDefaultFunctionValidity(f, 69 impl.symbolId[FullyQualifiedNameType(f.name)], sym); 70 } 71 } 72 } 73 74 void generateConfigForFunctionValidityFromUser(T)(CFunction f, Symbol symbol, ref T sym) { 75 import std.algorithm : map; 76 import std.array : array; 77 import std.conv : to; 78 import std.range : enumerate; 79 import std.xml; 80 import cpptooling.data : getName; 81 82 // assuming that the fully qualified name is always valid xml 83 sym.tag.attr["name"] = symbol.fullyQualifiedName; 84 sym.tag.attr["id"] = symbol.sequenceId.to!string; 85 86 string[] param_ids = f.paramRange.enumerate.map!( 87 a => a.value.getName("param" ~ a.index.to!string)).array(); 88 89 if (symbol.hasFuzz) { 90 auto fuzz = new Element("fuzz"); 91 sym ~= fuzz; 92 fuzz.tag.attr["use"] = symbol.fuzz.use; 93 fuzz.tag.attr["include"] = symbol.fuzz.include; 94 } 95 96 foreach (idx, p; symbol.limits.enumerate) { 97 //TODO this sanity check should be at the translation stage. Not the code generation. 98 if (idx >= param_ids.length) { 99 logger.warningf("symbol '%s', too many parameter checkers. Discarding '%s'", 100 symbol.fullyQualifiedName, p.identifier); 101 continue; 102 } else if (param_ids[idx] != p.identifier) { 103 logger.infof("symbol '%s', parameter identifier '%s' do not match the functions parameter '%s'", 104 f.name, p.identifier, param_ids[idx]); 105 } 106 107 auto xparam = new Element("param"); 108 sym ~= xparam; 109 110 xparam.tag.attr["name"] = p.identifier; 111 112 if (p.hasCheck) { 113 auto valid = new Element("valid"); 114 xparam ~= valid; 115 valid.tag.attr["check"] = p.check; 116 valid.tag.attr["condition"] = p.condition; 117 } 118 119 if (p.hasFuzz) { 120 auto fuzz = new Element("fuzz"); 121 xparam ~= fuzz; 122 fuzz.tag.attr["use"] = p.fuzz.use; 123 fuzz.tag.attr["param"] = p.fuzz.param; 124 fuzz.tag.attr["include"] = p.fuzz.include; 125 } 126 } 127 } 128 129 void generateConfigDefaultFunctionValidity(T)(CFunction f, ulong seq_id, ref T sym) { 130 import std.conv : to; 131 import std.range : enumerate; 132 import std.xml; 133 import cpptooling.data : getName; 134 135 // assuming that the fully qualified name is always valid xml 136 sym.tag.attr["name"] = f.name; 137 sym.tag.attr["id"] = seq_id.to!string; 138 139 foreach (idx, p; f.paramRange.enumerate) { 140 auto xparam = new Element("param"); 141 sym ~= xparam; 142 143 xparam.tag.attr["name"] = p.getName("param" ~ idx.to!string); 144 145 auto valid = new Element("valid"); 146 xparam ~= valid; 147 valid.tag.attr["check"] = ""; 148 valid.tag.attr["condition"] = ""; 149 150 auto fuzz = new Element("fuzz"); 151 xparam ~= fuzz; 152 fuzz.tag.attr["use"] = ""; 153 fuzz.tag.attr["param"] = ""; 154 fuzz.tag.attr["include"] = ""; 155 } 156 }