1 /** 2 * Encapsulates file/line/column locations. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/location.d, _location.d) 8 * Documentation: https://dlang.org/phobos/dmd_location.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/location.d 10 */ 11 12 module dmd.location; 13 14 import dmd.common.outbuffer; 15 import dmd.root.filename; 16 17 version (DMDLIB) 18 { 19 version = LocOffset; 20 } 21 22 /// How code locations are formatted for diagnostic reporting 23 enum MessageStyle : ubyte 24 { 25 digitalmars, /// filename.d(line): message 26 gnu, /// filename.d:line: message, see https://www.gnu.org/prep/standards/html_node/Errors.html 27 } 28 29 /** 30 A source code location 31 32 Used for error messages, `__FILE__` and `__LINE__` tokens, `__traits(getLocation, XXX)`, 33 debug info etc. 34 */ 35 struct Loc 36 { 37 /// zero-terminated filename string, either absolute or relative to cwd 38 const(char)* filename; 39 uint linnum; /// line number, starting from 1 40 uint charnum; /// utf8 code unit index relative to start of line, starting from 1 41 version (LocOffset) 42 uint fileOffset; /// utf8 code unit index relative to start of file, starting from 0 43 44 static immutable Loc initial; /// use for default initialization of const ref Loc's 45 46 extern (C++) __gshared bool showColumns; 47 extern (C++) __gshared MessageStyle messageStyle; 48 49 nothrow: 50 51 /******************************* 52 * Configure how display is done 53 * Params: 54 * showColumns = when to display columns 55 * messageStyle = digitalmars or gnu style messages 56 */ 57 extern (C++) static void set(bool showColumns, MessageStyle messageStyle) 58 { 59 this.showColumns = showColumns; 60 this.messageStyle = messageStyle; 61 } 62 63 extern (D) this(const(char)* filename, uint linnum, uint charnum) pure 64 { 65 this.linnum = linnum; 66 this.charnum = charnum; 67 this.filename = filename; 68 } 69 70 extern (C++) const(char)* toChars( 71 bool showColumns = Loc.showColumns, 72 MessageStyle messageStyle = Loc.messageStyle) const pure nothrow 73 { 74 OutBuffer buf; 75 if (filename) 76 { 77 buf.writestring(filename); 78 } 79 if (linnum) 80 { 81 final switch (messageStyle) 82 { 83 case MessageStyle.digitalmars: 84 buf.writeByte('('); 85 buf.print(linnum); 86 if (showColumns && charnum) 87 { 88 buf.writeByte(','); 89 buf.print(charnum); 90 } 91 buf.writeByte(')'); 92 break; 93 case MessageStyle.gnu: // https://www.gnu.org/prep/standards/html_node/Errors.html 94 buf.writeByte(':'); 95 buf.print(linnum); 96 if (showColumns && charnum) 97 { 98 buf.writeByte(':'); 99 buf.print(charnum); 100 } 101 break; 102 } 103 } 104 return buf.extractChars(); 105 } 106 107 /** 108 * Checks for equivalence by comparing the filename contents (not the pointer) and character location. 109 * 110 * Note: 111 * - Uses case-insensitive comparison on Windows 112 * - Ignores `charnum` if `Columns` is false. 113 */ 114 extern (C++) bool equals(ref const(Loc) loc) const 115 { 116 return (!showColumns || charnum == loc.charnum) && 117 linnum == loc.linnum && 118 FileName.equals(filename, loc.filename); 119 } 120 121 /** 122 * `opEquals()` / `toHash()` for AA key usage 123 * 124 * Compare filename contents (case-sensitively on Windows too), not 125 * the pointer - a static foreach loop repeatedly mixing in a mixin 126 * may lead to multiple equivalent filenames (`foo.d-mixin-<line>`), 127 * e.g., for test/runnable/test18880.d. 128 */ 129 extern (D) bool opEquals(ref const(Loc) loc) const @trusted pure nothrow @nogc 130 { 131 import core.stdc.string : strcmp; 132 133 return charnum == loc.charnum && 134 linnum == loc.linnum && 135 (filename == loc.filename || 136 (filename && loc.filename && strcmp(filename, loc.filename) == 0)); 137 } 138 139 /// ditto 140 extern (D) size_t toHash() const @trusted pure nothrow 141 { 142 import dmd.root.string : toDString; 143 144 auto hash = hashOf(linnum); 145 hash = hashOf(charnum, hash); 146 hash = hashOf(filename.toDString, hash); 147 return hash; 148 } 149 150 /****************** 151 * Returns: 152 * true if Loc has been set to other than the default initialization 153 */ 154 bool isValid() const pure 155 { 156 return filename !is null; 157 } 158 }