1 /**
2 Date: 2015-2017, Joakim Brännström
3 License: MPL-2, Mozilla Public License 2.0
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 */
6 module dextool.type;
7 
8 public import dextool.compilation_db : FilterClangFlag;
9 
10 @safe:
11 
12 enum ExitStatusType {
13     Ok,
14     Errors
15 }
16 
17 /** Prefix used for prepending generated code with a unique string to avoid
18  * name collisions.
19  * See specific functions for how it is used.
20  */
21 struct StubPrefix {
22     string payload;
23     alias payload this;
24 }
25 
26 /// Prefix used for prepending generated files.
27 struct FilePrefix {
28     string payload;
29     alias payload this;
30 }
31 
32 struct MainFileName {
33     string payload;
34     alias payload this;
35 }
36 
37 struct MainName {
38     string payload;
39     alias payload this;
40 }
41 
42 struct MainNs {
43     string payload;
44     alias payload this;
45 }
46 
47 struct MainInterface {
48     string payload;
49     alias payload this;
50 }
51 
52 struct DextoolVersion {
53     string payload;
54     alias payload this;
55 }
56 
57 struct CustomHeader {
58     string payload;
59     alias payload this;
60 }
61 
62 /// The raw arguments from the command line.
63 struct RawCliArguments {
64     string[] payload;
65     alias payload this;
66 }
67 
68 /// Used when writing data to files on the filesystem.
69 enum WriteStrategy {
70     overwrite,
71     skip
72 }
73 
74 //TODO remove FileNames
75 struct FileNames {
76     string[] payload;
77     alias payload this;
78 }
79 
80 struct InFiles {
81     string[] payload;
82     alias payload this;
83 }
84 
85 /// No guarantee regarding the path. May be absolute, relative, contain a '~'.
86 /// The user of this type must do all the safety checks to ensure that the
87 /// datacontained in valid.
88 struct Path {
89     string payload;
90     alias payload this;
91 }
92 
93 /// ditto
94 struct DirName {
95     Path payload;
96     alias payload this;
97 
98     pure nothrow @nogc this(string p) {
99         payload = Path(p);
100     }
101 }
102 
103 /// ditto
104 struct FileName {
105 pure @nogc nothrow:
106 
107     Path payload;
108     alias payload this;
109 
110     this(Path p) {
111         payload = p;
112     }
113 
114     pure nothrow @nogc this(string p) {
115         payload = Path(p);
116     }
117 }
118 
119 /** The path is guaranteed to be the absolute path.
120  *
121  * The user of the type has to make an explicit judgment when using the
122  * assignment operator. Either a `FileName` and then pay the cost of the path
123  * expansion or an absolute which is already assured to be _ok_.
124  * This divides the domain in two, one unchecked and one checked.
125  */
126 struct AbsolutePath {
127     import std.path : buildNormalizedPath, asAbsolutePath, asNormalizedPath;
128     import std.utf : toUTF8;
129 
130     Path payload;
131     alias payload this;
132 
133     invariant {
134         import std.path : isAbsolute;
135 
136         assert(payload.length == 0 || payload.isAbsolute);
137     }
138 
139     this(Path p) {
140         // the second buildNormalizedPath is needed to correctly resolve "."
141         // otherwise it is resolved to /foo/bar/.
142         payload = buildNormalizedPath(expand(p)).asAbsolutePath.asNormalizedPath.toUTF8.Path;
143     }
144 
145     /// Build the normalised path from workdir.
146     this(Path p, DirName workdir) {
147         // the second buildNormalizedPath is needed to correctly resolve "."
148         // otherwise it is resolved to /foo/bar/.
149         payload = buildNormalizedPath(expand(workdir), expand(p))
150             .asAbsolutePath.asNormalizedPath.toUTF8.Path;
151     }
152 
153     void opAssign(FileName p) {
154         payload = typeof(this)(p).payload;
155     }
156 
157     pure nothrow @nogc void opAssign(AbsolutePath p) {
158         payload = p.payload;
159     }
160 
161     pure nothrow const @nogc FileName opCast(T : FileName)() {
162         return FileName(payload);
163     }
164 
165     pure nothrow const @nogc string opCast(T : string)() {
166         return payload;
167     }
168 
169     private static Path expand(Path p) @trusted {
170         import std.path : expandTilde;
171 
172         return p.expandTilde.Path;
173     }
174 }
175 
176 struct AbsoluteFileName {
177     AbsolutePath payload;
178     alias payload this;
179 
180     pure nothrow @nogc this(AbsolutePath p) {
181         payload = p;
182     }
183 }
184 
185 struct AbsoluteDirectory {
186     AbsolutePath payload;
187     alias payload this;
188 
189     pure nothrow @nogc this(AbsolutePath p) {
190         payload = p;
191     }
192 }
193 
194 /** During construction checks that the file exists on the filesystem.
195  *
196  * If it doesn't exist it will throw an Exception.
197  */
198 struct Exists(T) {
199     AbsolutePath payload;
200     alias payload this;
201 
202     this(AbsolutePath p) {
203         import std.file : exists, FileException;
204 
205         if (!exists(p)) {
206             throw new FileException("File do not exist: " ~ cast(string) p);
207         }
208 
209         payload = p;
210     }
211 
212     this(Exists!T p) {
213         payload = p.payload;
214     }
215 
216     void opAssign(Exists!T p) pure nothrow @nogc {
217         payload = p;
218     }
219 }
220 
221 auto makeExists(T)(T p) {
222     return Exists!T(p);
223 }
224 
225 @("shall always be the absolute path")
226 unittest {
227     import std.algorithm : canFind;
228     import std.path;
229     import unit_threaded;
230 
231     AbsolutePath(FileName("~/foo")).canFind('~').shouldEqual(false);
232     AbsolutePath(FileName("foo")).isAbsolute.shouldEqual(true);
233 }
234 
235 @("shall expand . without any trailing /.")
236 unittest {
237     import std.algorithm : canFind;
238     import unit_threaded;
239 
240     AbsolutePath(FileName(".")).canFind('.').shouldBeFalse;
241     AbsolutePath(FileName("."), DirName(".")).canFind('.').shouldBeFalse;
242 }
243 
244 @("shall be an instantiation of Exists")
245 nothrow unittest {
246     // the file is not expected to exist.
247 
248     try {
249         auto p = makeExists(AbsolutePath(FileName("foo")));
250     } catch (Exception e) {
251     }
252 }