1 /**
2 Copyright: Copyright (c) 2015-2016, Joakim Brännström. All rights reserved.
3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 */
6 module clang.SourceRange;
7 
8 import std.conv;
9 import std.string;
10 import std.experimental.logger;
11 
12 import clang.c.Index;
13 
14 import clang.SourceLocation;
15 
16 ///
17 struct SourceRange {
18     import std.format : FormatSpec;
19     import clang.Util;
20 
21     mixin CX;
22 
23     /// Retrieve a NULL (invalid) source range.
24     static SourceRange empty() @trusted {
25         auto r = clang_getNullRange();
26         return SourceRange(r);
27     }
28 
29     /// Retrieve a source location representing the first character within a source range.
30     @property SourceLocation start() const @trusted {
31         auto r = clang_getRangeStart(cx);
32         return SourceLocation(r);
33     }
34 
35     /// Retrieve a source location representing the last character within a source range.
36     @property SourceLocation end() const @trusted {
37         auto r = clang_getRangeEnd(cx);
38         return SourceLocation(r);
39     }
40 
41     @property string path() const @trusted {
42         return start.path;
43     }
44 
45     ///
46     bool isNull() const @trusted {
47         return clang_Range_isNull(cx) != 0;
48     }
49 
50     ///
51     equals_t opEquals(const ref SourceRange range2) const {
52         return clang_equalRanges(cast(CXSourceRange) cx, cast(CXSourceRange) range2) != 0;
53     }
54 
55     string toString() @safe const {
56         import std.exception : assumeUnique;
57         import std.format : FormatSpec;
58 
59         char[] buf;
60         buf.reserve(100);
61         auto fmt = FormatSpec!char("%s");
62         toString((const(char)[] s) { buf ~= s; }, fmt);
63         auto trustedUnique(T)(T t) @trusted {
64             return assumeUnique(t);
65         }
66 
67         return trustedUnique(buf);
68     }
69 
70     void toString(Writer, Char)(scope Writer w, FormatSpec!Char fmt) const {
71         import std.format : formattedWrite;
72 
73         auto start = this.start.presumed;
74         auto end = this.end.presumed;
75 
76         if (isValid) {
77             formattedWrite(w, "%s [start='%s:%s' end='%s:%s']", start.file,
78                     start.line, start.column, end.line, end.column);
79         } else {
80             formattedWrite(w, "%s(%s)", typeid(this), cx);
81         }
82     }
83 }
84 
85 /** Check if two source ranges intersect
86  */
87 bool intersects(in SourceRange a, in SourceRange b) {
88     return a.path == b.path && a.end.offset >= b.start.offset && b.end.offset >= a.start.offset;
89 }
90 
91 /// Retrieve a source range given the beginning and ending source locations.
92 SourceRange range(ref SourceLocation begin, SourceLocation end) {
93     auto r = clang_getRange(begin.cx, end.cx);
94     return SourceRange(r);
95 }
96 
97 unittest {
98     // Test of null range.
99     auto r = SourceRange.empty();
100 
101     assert(r.isNull == true);
102 }