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 This file contains a visitor to extract the include directives.
11 */
12 module cpptooling.analyzer.clang.include_visitor;
13 
14 import std.typecons : Nullable;
15 import std.algorithm : until, filter;
16 
17 import clang.Cursor : Cursor;
18 import clang.c.Index;
19 
20 import cpptooling.analyzer.clang.cursor_visitor;
21 import dextool.type : FileName;
22 
23 /** Extract the filenames from all `#include` preprocessor macros that are
24  * found in the AST.
25  *
26  * Note that this is the filename inside the "", not the actuall path on the
27  * filesystem.
28  *
29  * Params:
30  *  root = clang AST
31  *  depth = how deep into the AST to analyze.
32  */
33 FileName[] extractIncludes(Cursor root, int depth = 2) {
34     import std.array : appender;
35 
36     auto r = appender!(FileName[])();
37 
38     foreach (c; root.visitBreathFirst.filter!(a => a.kind == CXCursorKind.inclusionDirective)) {
39         r.put(FileName(c.spelling));
40     }
41 
42     return r.data;
43 }
44 
45 /** Analyze the AST (root) to see if any of the `#include` fulfill the user supplied matcher.
46  *
47  * Params:
48  *  root = clang AST
49  *  depth = how deep into the AST to analyze.
50  * Returns: the path to the header file that matched the predicate
51  */
52 Nullable!FileName hasInclude(alias matcher)(Cursor root, int depth = 2) @trusted {
53     Nullable!FileName r;
54 
55     foreach (c; root.visitBreathFirst.filter!(a => a.kind == CXCursorKind.inclusionDirective)) {
56         if (matcher(c.spelling)) {
57             r = FileName(c.include.file.name);
58             break;
59         }
60     }
61 
62     return r;
63 }