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");