1 /** 2 Date: 2015-2017, Joakim Brännström 3 License: MPL-2, Mozilla Public License 2.0 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 */ 6 module dextool.utility; 7 8 import logger = std.experimental.logger; 9 10 import dextool.compilation_db : CompileCommandDB, CompileCommand, orDefaultDb, 11 fromFiles; 12 13 public import dextool.type : AbsolutePath, DextoolVersion, ExitStatusType; 14 15 @safe: 16 17 enum PreferLang : string { 18 none = "", 19 c = "-xc", 20 cpp = "-xc++" 21 } 22 23 pure string[] prependDefaultFlags(const string[] in_cflags, const PreferLang lang) { 24 import std.algorithm : canFind; 25 26 immutable syntax_only = "-fsyntax-only"; 27 if (in_cflags.canFind(syntax_only)) { 28 return prependLangFlagIfMissing(in_cflags, lang); 29 } else { 30 return syntax_only ~ prependLangFlagIfMissing(in_cflags, lang); 31 } 32 } 33 34 ///TODO move to clang module. 35 pure string[] prependLangFlagIfMissing(in string[] in_cflags, const PreferLang lang) { 36 import std.algorithm : findAmong; 37 38 auto v = findAmong(in_cflags, [PreferLang.c, PreferLang.cpp]); 39 40 if (v.length == 0) { 41 return [cast(string) lang] ~ in_cflags; 42 } 43 44 return in_cflags.dup; 45 } 46 47 @system unittest { 48 import test.extra_should : shouldEqualPretty; 49 50 auto cflags = ["-DBEFORE", "-xc++", "-DAND_A_DEFINE", "-I/3906164"]; 51 cflags.shouldEqualPretty(prependLangFlagIfMissing(cflags, PreferLang.c)); 52 } 53 54 /** Apply the visitor on the clang AST derived from the input_file. 55 * 56 * Params: 57 * input_file = path to a file to analyze 58 * cflags = compiler flags to pass on to clang 59 * visitor = to apply on the clang AST 60 * ctx = $(D ClangContext) 61 * 62 * Returns: if the analyze was performed ok or errors occured 63 */ 64 ExitStatusType analyzeFile(VisitorT, ClangContextT)(const AbsolutePath input_file, 65 const string[] cflags, VisitorT visitor, ref ClangContextT ctx) { 66 import std.file : exists; 67 68 import cpptooling.analyzer.clang.ast : ClangAST; 69 import cpptooling.analyzer.clang.check_parse_result : hasParseErrors, 70 logDiagnostic; 71 72 if (!exists(input_file)) { 73 logger.errorf("File '%s' do not exist", input_file); 74 return ExitStatusType.Errors; 75 } 76 77 logger.infof("Analyzing '%s'", input_file); 78 79 auto translation_unit = ctx.makeTranslationUnit(input_file, cflags); 80 if (translation_unit.hasParseErrors) { 81 logDiagnostic(translation_unit); 82 logger.error("Compile error..."); 83 return ExitStatusType.Errors; 84 } 85 86 auto ast = ClangAST!VisitorT(translation_unit.cursor); 87 ast.accept(visitor); 88 89 return ExitStatusType.Ok; 90 } 91 92 // this is deprecated 93 public import dextool.compilation_db : fromArgCompileDb; 94 95 /// Version derived from the git archive. 96 import std..string : strip; 97 98 enum dextoolVersion = DextoolVersion(import("version.txt").strip); 99 100 static assert(dextoolVersion.length > 0, "Failed to import version.txt at compile time");