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