1 /** 2 * Copyright: Copyright (c) 2011 Jacob Carlborg. All rights reserved. 3 * Authors: Jacob Carlborg, Joakim Brännström (joakim.brannstrom dottli gmx.com) 4 * Version: 1.1 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 6 * History: 7 * 1.0 initial release. 2012-01-29 $(BR) 8 * Jacob Carlborg 9 * 10 * 1.1 additional features missing compared to cindex.py. 2015-03-07 $(BR) 11 * Joakim Brännström 12 */ 13 module clang.SourceLocation; 14 15 import std.typecons; 16 17 import clang.c.Index; 18 19 import clang.File; 20 import clang.TranslationUnit; 21 import clang.Util; 22 23 /// A SourceLocation represents a particular location within a source file. 24 struct SourceLocation { 25 import std.format : FormatSpec, format, formattedWrite, formatValue; 26 27 mixin CX; 28 29 struct Location { 30 File file; 31 uint line; 32 uint column; 33 uint offset; 34 35 string toString() @safe const { 36 import std.exception : assumeUnique; 37 import std.format : FormatSpec; 38 39 char[] buf; 40 buf.reserve(100); 41 auto fmt = FormatSpec!char("%s"); 42 toString((const(char)[] s) { buf ~= s; }, fmt); 43 auto trustedUnique(T)(T t) @trusted { 44 return assumeUnique(t); 45 } 46 47 return trustedUnique(buf); 48 } 49 50 void toString(Writer, Char)(scope Writer w, FormatSpec!Char fmt) const { 51 formattedWrite(w, "[%s line=%d column=%d offset=%d]", file.name, line, column, offset); 52 } 53 } 54 55 // ugly hack. Must fix to something that works for both File and string. 56 struct Location2 { 57 string file; 58 uint line; 59 uint column; 60 uint offset; 61 62 string toString() @safe const { 63 import std.exception : assumeUnique; 64 import std.format : FormatSpec; 65 66 char[] buf; 67 buf.reserve(100); 68 auto fmt = FormatSpec!char("%s"); 69 toString((const(char)[] s) { buf ~= s; }, fmt); 70 auto trustedUnique(T)(T t) @trusted { 71 return assumeUnique(t); 72 } 73 74 return trustedUnique(buf); 75 } 76 77 void toString(Writer, Char)(scope Writer w, FormatSpec!Char fmt) const { 78 formattedWrite(w, "[%s line=%d column=%d offset=%d]", file, line, column, offset); 79 } 80 } 81 82 /// Retrieve a NULL (invalid) source location. 83 static SourceLocation empty() { 84 auto r = clang_getNullLocation(); 85 return SourceLocation(r); 86 } 87 88 /** Retrieves the source location associated with a given file/line/column 89 * in a particular translation unit. 90 * TODO consider moving to TranslationUnit instead 91 * 92 * Params: 93 * tu = translation unit to derive location from. 94 * file = a file in tu. 95 * line = text line. Starting at 1. 96 * offset = offset into the line. Starting at 1. 97 */ 98 static Nullable!SourceLocation fromPosition(ref TranslationUnit tu, 99 ref File file, uint line, uint offset) { 100 101 auto rval = Nullable!SourceLocation(); 102 auto r = SourceLocation(clang_getLocation(tu, file, line, offset)); 103 if (r.file !is null) { 104 rval = SourceLocation(r); 105 } 106 107 return rval; 108 } 109 110 /** Retrieves the source location associated with a given character offset 111 * in a particular translation unit. 112 * TODO consider moving to TranslationUnit instead 113 */ 114 static SourceLocation fromOffset(ref TranslationUnit tu, ref File file, uint offset) { 115 auto r = clang_getLocationForOffset(tu, file, offset); 116 return SourceLocation(r); 117 } 118 119 /// Get the file represented by this source location. 120 /// TODO implement with a cache, this is inefficient. 121 @property File file() const @safe { 122 return spelling.file; 123 } 124 125 /// Get the line represented by this source location. 126 @property uint line() const @trusted { 127 uint result; 128 clang_getSpellingLocation(cx, null, &result, null, null); 129 return result; 130 } 131 132 /// Get the column represented by this source location. 133 @property uint column() const @trusted { 134 uint result; 135 clang_getSpellingLocation(cx, null, null, &result, null); 136 return result; 137 } 138 139 /// Get the file offset represented by this source location. 140 @property uint offset() const @trusted { 141 uint result; 142 clang_getSpellingLocation(cx, null, null, null, &result); 143 return result; 144 } 145 146 /// The path the SourceLocation point to. 147 @property string path() const @trusted { 148 File file; 149 clang_getSpellingLocation(cx, &file.cx, null, null, null); 150 return file.name; 151 } 152 153 /** Returns if the given source location is in the main file of the 154 * corresponding translation unit. 155 */ 156 @property bool isFromMainFile() const @trusted { 157 return clang_Location_isFromMainFile(cx) != 0; 158 } 159 160 /** Retrieve the file, line, column, and offset represented by 161 * the given source location. 162 * 163 * If the location refers into a macro expansion, retrieves the 164 * location of the macro expansion. 165 * 166 * Location within a source file that will be decomposed into its parts. 167 * 168 * file [out] if non-NULL, will be set to the file to which the given 169 * source location points. 170 * 171 * line [out] if non-NULL, will be set to the line to which the given 172 * source location points. 173 * 174 * column [out] if non-NULL, will be set to the column to which the given 175 * source location points. 176 * 177 * offset [out] if non-NULL, will be set to the offset into the 178 * buffer to which the given source location points. 179 */ 180 @property Location expansion() const @trusted { 181 Location data; 182 183 clang_getExpansionLocation(cx, &data.file.cx, &data.line, &data.column, &data.offset); 184 185 return data; 186 } 187 188 /** Retrieve the file, line, column, and offset represented by 189 * the given source location, as specified in a # line directive. 190 * 191 * Example: given the following source code in a file somefile.c 192 * --- 193 * #123 "dummy.c" 1 194 * 195 * static int func() 196 * { 197 * return 0; 198 * } 199 * --- 200 * the location information returned by this function would be 201 * --- 202 * File: dummy.c Line: 124 Column: 12 203 * --- 204 * whereas clang_getExpansionLocation would have returned 205 * --- 206 * File: somefile.c Line: 3 Column: 12 207 * --- 208 * 209 * filename [out] if non-NULL, will be set to the filename of the 210 * source location. Note that filenames returned will be for "virtual" files, 211 * which don't necessarily exist on the machine running clang - e.g. when 212 * parsing preprocessed output obtained from a different environment. If 213 * a non-NULL value is passed in, remember to dispose of the returned value 214 * using \c clang_disposeString() once you've finished with it. For an invalid 215 * source location, an empty string is returned. 216 * 217 * line [out] if non-NULL, will be set to the line number of the 218 * source location. For an invalid source location, zero is returned. 219 * 220 * column [out] if non-NULL, will be set to the column number of the 221 * source location. For an invalid source location, zero is returned. 222 */ 223 auto presumed() const @trusted { 224 Location2 data; 225 CXString cxstring; 226 227 clang_getPresumedLocation(cx, &cxstring, &data.line, &data.column); 228 data.file = toD(cxstring); 229 230 return data; 231 } 232 233 /** Retrieve the file, line, column, and offset represented by 234 * the given source location. 235 * 236 * If the location refers into a macro instantiation, return where the 237 * location was originally spelled in the source file. 238 * 239 * The location within a source file that will be decomposed into its 240 * parts. 241 * 242 * file [out] if non-NULL, will be set to the file to which the given 243 * source location points. 244 * 245 * line [out] if non-NULL, will be set to the line to which the given 246 * source location points. 247 * 248 * column [out] if non-NULL, will be set to the column to which the given 249 * source location points. 250 * 251 * offset [out] if non-NULL, will be set to the offset into the 252 * buffer to which the given source location points. 253 */ 254 @property Location spelling() const @trusted { 255 Location data; 256 257 clang_getSpellingLocation(cx, &data.file.cx, &data.line, &data.column, &data.offset); 258 259 return data; 260 } 261 262 string toString() @safe const { 263 import std.exception : assumeUnique; 264 265 char[] buf; 266 buf.reserve(100); 267 auto fmt = FormatSpec!char("%s"); 268 toString((const(char)[] s) { buf ~= s; }, fmt); 269 auto trustedUnique(T)(T t) @trusted { 270 return assumeUnique(t); 271 } 272 273 return trustedUnique(buf); 274 } 275 276 void toString(Writer, Char)(scope Writer w, FormatSpec!Char fmt) const { 277 if (isValid) 278 formatValue(w, spelling, fmt); 279 } 280 }