/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Basic/SourceLocation.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===- SourceLocation.h - Compact identifier for Source Files ---*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | /// \file |
10 | | /// Defines the clang::SourceLocation class and associated facilities. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #ifndef LLVM_CLANG_BASIC_SOURCELOCATION_H |
15 | | #define LLVM_CLANG_BASIC_SOURCELOCATION_H |
16 | | |
17 | | #include "clang/Basic/LLVM.h" |
18 | | #include "llvm/ADT/StringRef.h" |
19 | | #include <cassert> |
20 | | #include <cstdint> |
21 | | #include <string> |
22 | | #include <utility> |
23 | | |
24 | | namespace llvm { |
25 | | |
26 | | class FoldingSetNodeID; |
27 | | template <typename T, typename Enable> struct FoldingSetTrait; |
28 | | |
29 | | } // namespace llvm |
30 | | |
31 | | namespace clang { |
32 | | |
33 | | class SourceManager; |
34 | | |
35 | | /// An opaque identifier used by SourceManager which refers to a |
36 | | /// source file (MemoryBuffer) along with its \#include path and \#line data. |
37 | | /// |
38 | | class FileID { |
39 | | /// A mostly-opaque identifier, where 0 is "invalid", >0 is |
40 | | /// this module, and <-1 is something loaded from another module. |
41 | | int ID = 0; |
42 | | |
43 | | public: |
44 | 9.08M | bool isValid() const { return ID != 0; } |
45 | 273M | bool isInvalid() const { return ID == 0; } |
46 | | |
47 | 1.12G | bool operator==(const FileID &RHS) const { return ID == RHS.ID; } |
48 | 2.97G | bool operator<(const FileID &RHS) const { return ID < RHS.ID; } |
49 | 0 | bool operator<=(const FileID &RHS) const { return ID <= RHS.ID; } |
50 | 52.3M | bool operator!=(const FileID &RHS) const { return !(*this == RHS); } |
51 | 0 | bool operator>(const FileID &RHS) const { return RHS < *this; } |
52 | 0 | bool operator>=(const FileID &RHS) const { return RHS <= *this; } |
53 | | |
54 | 52.8M | static FileID getSentinel() { return get(-1); } |
55 | 52.4M | unsigned getHashValue() const { return static_cast<unsigned>(ID); } |
56 | | |
57 | | private: |
58 | | friend class ASTWriter; |
59 | | friend class ASTReader; |
60 | | friend class SourceManager; |
61 | | |
62 | 748M | static FileID get(int V) { |
63 | 748M | FileID F; |
64 | 748M | F.ID = V; |
65 | 748M | return F; |
66 | 748M | } |
67 | | |
68 | 27.8k | int getOpaqueValue() const { return ID; } |
69 | | }; |
70 | | |
71 | | /// Encodes a location in the source. The SourceManager can decode this |
72 | | /// to get at the full include stack, line and column information. |
73 | | /// |
74 | | /// Technically, a source location is simply an offset into the manager's view |
75 | | /// of the input source, which is all input buffers (including macro |
76 | | /// expansions) concatenated in an effectively arbitrary order. The manager |
77 | | /// actually maintains two blocks of input buffers. One, starting at offset |
78 | | /// 0 and growing upwards, contains all buffers from this module. The other, |
79 | | /// starting at the highest possible offset and growing downwards, contains |
80 | | /// buffers of loaded modules. |
81 | | /// |
82 | | /// In addition, one bit of SourceLocation is used for quick access to the |
83 | | /// information whether the location is in a file or a macro expansion. |
84 | | /// |
85 | | /// It is important that this type remains small. It is currently 32 bits wide. |
86 | | class SourceLocation { |
87 | | friend class ASTReader; |
88 | | friend class ASTWriter; |
89 | | friend class SourceManager; |
90 | | friend struct llvm::FoldingSetTrait<SourceLocation, void>; |
91 | | |
92 | | public: |
93 | | using UIntTy = uint32_t; |
94 | | using IntTy = int32_t; |
95 | | |
96 | | private: |
97 | | UIntTy ID = 0; |
98 | | |
99 | | enum : UIntTy { MacroIDBit = 1ULL << (8 * sizeof(UIntTy) - 1) }; |
100 | | |
101 | | public: |
102 | 3.26G | bool isFileID() const { return (ID & MacroIDBit) == 0; } |
103 | 395M | bool isMacroID() const { return (ID & MacroIDBit) != 0; } |
104 | | |
105 | | /// Return true if this is a valid SourceLocation object. |
106 | | /// |
107 | | /// Invalid SourceLocations are often used when events have no corresponding |
108 | | /// location in the source (e.g. a diagnostic is required for a command line |
109 | | /// option). |
110 | 5.42G | bool isValid() const { return ID != 0; } |
111 | 1.22G | bool isInvalid() const { return ID == 0; } |
112 | | |
113 | | private: |
114 | | /// Return the offset into the manager's global input view. |
115 | 9.80G | UIntTy getOffset() const { return ID & ~MacroIDBit; } |
116 | | |
117 | 83.6M | static SourceLocation getFileLoc(UIntTy ID) { |
118 | 83.6M | assert((ID & MacroIDBit) == 0 && "Ran out of source locations!"); |
119 | 0 | SourceLocation L; |
120 | 83.6M | L.ID = ID; |
121 | 83.6M | return L; |
122 | 83.6M | } |
123 | | |
124 | 139M | static SourceLocation getMacroLoc(UIntTy ID) { |
125 | 139M | assert((ID & MacroIDBit) == 0 && "Ran out of source locations!"); |
126 | 0 | SourceLocation L; |
127 | 139M | L.ID = MacroIDBit | ID; |
128 | 139M | return L; |
129 | 139M | } |
130 | | |
131 | | public: |
132 | | /// Return a source location with the specified offset from this |
133 | | /// SourceLocation. |
134 | 2.64G | SourceLocation getLocWithOffset(IntTy Offset) const { |
135 | 2.64G | assert(((getOffset()+Offset) & MacroIDBit) == 0 && "offset overflow"); |
136 | 0 | SourceLocation L; |
137 | 2.64G | L.ID = ID+Offset; |
138 | 2.64G | return L; |
139 | 2.64G | } |
140 | | |
141 | | /// When a SourceLocation itself cannot be used, this returns |
142 | | /// an (opaque) 32-bit integer encoding for it. |
143 | | /// |
144 | | /// This should only be passed to SourceLocation::getFromRawEncoding, it |
145 | | /// should not be inspected directly. |
146 | 4.57G | UIntTy getRawEncoding() const { return ID; } |
147 | | |
148 | | /// Turn a raw encoding of a SourceLocation object into |
149 | | /// a real SourceLocation. |
150 | | /// |
151 | | /// \see getRawEncoding. |
152 | 4.86G | static SourceLocation getFromRawEncoding(UIntTy Encoding) { |
153 | 4.86G | SourceLocation X; |
154 | 4.86G | X.ID = Encoding; |
155 | 4.86G | return X; |
156 | 4.86G | } |
157 | | |
158 | | /// When a SourceLocation itself cannot be used, this returns |
159 | | /// an (opaque) pointer encoding for it. |
160 | | /// |
161 | | /// This should only be passed to SourceLocation::getFromPtrEncoding, it |
162 | | /// should not be inspected directly. |
163 | 17.0k | void* getPtrEncoding() const { |
164 | | // Double cast to avoid a warning "cast to pointer from integer of different |
165 | | // size". |
166 | 17.0k | return (void*)(uintptr_t)getRawEncoding(); |
167 | 17.0k | } |
168 | | |
169 | | /// Turn a pointer encoding of a SourceLocation object back |
170 | | /// into a real SourceLocation. |
171 | 13.4k | static SourceLocation getFromPtrEncoding(const void *Encoding) { |
172 | 13.4k | return getFromRawEncoding((SourceLocation::UIntTy)(uintptr_t)Encoding); |
173 | 13.4k | } |
174 | | |
175 | 3.29k | static bool isPairOfFileLocations(SourceLocation Start, SourceLocation End) { |
176 | 3.29k | return Start.isValid() && Start.isFileID() && End.isValid() && |
177 | 3.29k | End.isFileID(); |
178 | 3.29k | } |
179 | | |
180 | | unsigned getHashValue() const; |
181 | | void print(raw_ostream &OS, const SourceManager &SM) const; |
182 | | std::string printToString(const SourceManager &SM) const; |
183 | | void dump(const SourceManager &SM) const; |
184 | | }; |
185 | | |
186 | 229M | inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) { |
187 | 229M | return LHS.getRawEncoding() == RHS.getRawEncoding(); |
188 | 229M | } |
189 | | |
190 | 1.70M | inline bool operator!=(const SourceLocation &LHS, const SourceLocation &RHS) { |
191 | 1.70M | return !(LHS == RHS); |
192 | 1.70M | } |
193 | | |
194 | | // Ordering is meaningful only if LHS and RHS have the same FileID! |
195 | | // Otherwise use SourceManager::isBeforeInTranslationUnit(). |
196 | 2.00M | inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) { |
197 | 2.00M | return LHS.getRawEncoding() < RHS.getRawEncoding(); |
198 | 2.00M | } |
199 | 0 | inline bool operator>(const SourceLocation &LHS, const SourceLocation &RHS) { |
200 | 0 | return LHS.getRawEncoding() > RHS.getRawEncoding(); |
201 | 0 | } |
202 | 969 | inline bool operator<=(const SourceLocation &LHS, const SourceLocation &RHS) { |
203 | 969 | return LHS.getRawEncoding() <= RHS.getRawEncoding(); |
204 | 969 | } |
205 | 14 | inline bool operator>=(const SourceLocation &LHS, const SourceLocation &RHS) { |
206 | 14 | return LHS.getRawEncoding() >= RHS.getRawEncoding(); |
207 | 14 | } |
208 | | |
209 | | /// A trivial tuple used to represent a source range. |
210 | | class SourceRange { |
211 | | SourceLocation B; |
212 | | SourceLocation E; |
213 | | |
214 | | public: |
215 | 2.42G | SourceRange() = default; |
216 | 96.9M | SourceRange(SourceLocation loc) : B(loc), E(loc) {} |
217 | 784M | SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {} |
218 | | |
219 | 1.00G | SourceLocation getBegin() const { return B; } |
220 | 398M | SourceLocation getEnd() const { return E; } |
221 | | |
222 | 144M | void setBegin(SourceLocation b) { B = b; } |
223 | 391M | void setEnd(SourceLocation e) { E = e; } |
224 | | |
225 | 791M | bool isValid() const { return B.isValid() && E.isValid()74.0M ; } |
226 | 526M | bool isInvalid() const { return !isValid(); } |
227 | | |
228 | 17.8M | bool operator==(const SourceRange &X) const { |
229 | 17.8M | return B == X.B && E == X.E17.8M ; |
230 | 17.8M | } |
231 | | |
232 | 10 | bool operator!=(const SourceRange &X) const { |
233 | 10 | return B != X.B || E != X.E; |
234 | 10 | } |
235 | | |
236 | | // Returns true iff other is wholly contained within this range. |
237 | 0 | bool fullyContains(const SourceRange &other) const { |
238 | 0 | return B <= other.B && E >= other.E; |
239 | 0 | } |
240 | | |
241 | | void print(raw_ostream &OS, const SourceManager &SM) const; |
242 | | std::string printToString(const SourceManager &SM) const; |
243 | | void dump(const SourceManager &SM) const; |
244 | | }; |
245 | | |
246 | | /// Represents a character-granular source range. |
247 | | /// |
248 | | /// The underlying SourceRange can either specify the starting/ending character |
249 | | /// of the range, or it can specify the start of the range and the start of the |
250 | | /// last token of the range (a "token range"). In the token range case, the |
251 | | /// size of the last token must be measured to determine the actual end of the |
252 | | /// range. |
253 | | class CharSourceRange { |
254 | | SourceRange Range; |
255 | | bool IsTokenRange = false; |
256 | | |
257 | | public: |
258 | 904k | CharSourceRange() = default; |
259 | 31.4M | CharSourceRange(SourceRange R, bool ITR) : Range(R), IsTokenRange(ITR) {} |
260 | | |
261 | 2.15M | static CharSourceRange getTokenRange(SourceRange R) { |
262 | 2.15M | return CharSourceRange(R, true); |
263 | 2.15M | } |
264 | | |
265 | 8.36M | static CharSourceRange getCharRange(SourceRange R) { |
266 | 8.36M | return CharSourceRange(R, false); |
267 | 8.36M | } |
268 | | |
269 | 1.37k | static CharSourceRange getTokenRange(SourceLocation B, SourceLocation E) { |
270 | 1.37k | return getTokenRange(SourceRange(B, E)); |
271 | 1.37k | } |
272 | | |
273 | 8.33M | static CharSourceRange getCharRange(SourceLocation B, SourceLocation E) { |
274 | 8.33M | return getCharRange(SourceRange(B, E)); |
275 | 8.33M | } |
276 | | |
277 | | /// Return true if the end of this range specifies the start of |
278 | | /// the last token. Return false if the end of this range specifies the last |
279 | | /// character in the range. |
280 | 7.65M | bool isTokenRange() const { return IsTokenRange; } |
281 | 6.55k | bool isCharRange() const { return !IsTokenRange; } |
282 | | |
283 | 42.3M | SourceLocation getBegin() const { return Range.getBegin(); } |
284 | 37.3M | SourceLocation getEnd() const { return Range.getEnd(); } |
285 | 4.19k | SourceRange getAsRange() const { return Range; } |
286 | | |
287 | 3.94M | void setBegin(SourceLocation b) { Range.setBegin(b); } |
288 | 3.07M | void setEnd(SourceLocation e) { Range.setEnd(e); } |
289 | 3.07M | void setTokenRange(bool TR) { IsTokenRange = TR; } |
290 | | |
291 | 4.62M | bool isValid() const { return Range.isValid(); } |
292 | 4.13M | bool isInvalid() const { return !isValid(); } |
293 | | }; |
294 | | |
295 | | /// Represents an unpacked "presumed" location which can be presented |
296 | | /// to the user. |
297 | | /// |
298 | | /// A 'presumed' location can be modified by \#line and GNU line marker |
299 | | /// directives and is always the expansion point of a normal location. |
300 | | /// |
301 | | /// You can get a PresumedLoc from a SourceLocation with SourceManager. |
302 | | class PresumedLoc { |
303 | | const char *Filename = nullptr; |
304 | | FileID ID; |
305 | | unsigned Line, Col; |
306 | | SourceLocation IncludeLoc; |
307 | | |
308 | | public: |
309 | 31.8k | PresumedLoc() = default; |
310 | | PresumedLoc(const char *FN, FileID FID, unsigned Ln, unsigned Co, |
311 | | SourceLocation IL) |
312 | 109M | : Filename(FN), ID(FID), Line(Ln), Col(Co), IncludeLoc(IL) {} |
313 | | |
314 | | /// Return true if this object is invalid or uninitialized. |
315 | | /// |
316 | | /// This occurs when created with invalid source locations or when walking |
317 | | /// off the top of a \#include stack. |
318 | 91.9M | bool isInvalid() const { return Filename == nullptr; } |
319 | 122M | bool isValid() const { return Filename != nullptr; } |
320 | | |
321 | | /// Return the presumed filename of this location. |
322 | | /// |
323 | | /// This can be affected by \#line etc. |
324 | 99.5M | const char *getFilename() const { |
325 | 99.5M | assert(isValid()); |
326 | 0 | return Filename; |
327 | 99.5M | } |
328 | | |
329 | 7.85M | FileID getFileID() const { |
330 | 7.85M | assert(isValid()); |
331 | 0 | return ID; |
332 | 7.85M | } |
333 | | |
334 | | /// Return the presumed line number of this location. |
335 | | /// |
336 | | /// This can be affected by \#line etc. |
337 | 10.8M | unsigned getLine() const { |
338 | 10.8M | assert(isValid()); |
339 | 0 | return Line; |
340 | 10.8M | } |
341 | | |
342 | | /// Return the presumed column number of this location. |
343 | | /// |
344 | | /// This cannot be affected by \#line, but is packaged here for convenience. |
345 | 2.14M | unsigned getColumn() const { |
346 | 2.14M | assert(isValid()); |
347 | 0 | return Col; |
348 | 2.14M | } |
349 | | |
350 | | /// Return the presumed include location of this location. |
351 | | /// |
352 | | /// This can be affected by GNU linemarker directives. |
353 | 124k | SourceLocation getIncludeLoc() const { |
354 | 124k | assert(isValid()); |
355 | 0 | return IncludeLoc; |
356 | 124k | } |
357 | | }; |
358 | | |
359 | | class FileEntry; |
360 | | |
361 | | /// A SourceLocation and its associated SourceManager. |
362 | | /// |
363 | | /// This is useful for argument passing to functions that expect both objects. |
364 | | /// |
365 | | /// This class does not guarantee the presence of either the SourceManager or |
366 | | /// a valid SourceLocation. Clients should use `isValid()` and `hasManager()` |
367 | | /// before calling the member functions. |
368 | | class FullSourceLoc : public SourceLocation { |
369 | | const SourceManager *SrcMgr = nullptr; |
370 | | |
371 | | public: |
372 | | /// Creates a FullSourceLoc where isValid() returns \c false. |
373 | 92.8k | FullSourceLoc() = default; |
374 | | |
375 | | explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM) |
376 | 656k | : SourceLocation(Loc), SrcMgr(&SM) {} |
377 | | |
378 | | /// Checks whether the SourceManager is present. |
379 | 23.4k | bool hasManager() const { return SrcMgr != nullptr; } |
380 | | |
381 | | /// \pre hasManager() |
382 | 302k | const SourceManager &getManager() const { |
383 | 302k | assert(SrcMgr && "SourceManager is NULL."); |
384 | 0 | return *SrcMgr; |
385 | 302k | } |
386 | | |
387 | | FileID getFileID() const; |
388 | | |
389 | | FullSourceLoc getExpansionLoc() const; |
390 | | FullSourceLoc getSpellingLoc() const; |
391 | | FullSourceLoc getFileLoc() const; |
392 | | PresumedLoc getPresumedLoc(bool UseLineDirectives = true) const; |
393 | | bool isMacroArgExpansion(FullSourceLoc *StartLoc = nullptr) const; |
394 | | FullSourceLoc getImmediateMacroCallerLoc() const; |
395 | | std::pair<FullSourceLoc, StringRef> getModuleImportLoc() const; |
396 | | unsigned getFileOffset() const; |
397 | | |
398 | | unsigned getExpansionLineNumber(bool *Invalid = nullptr) const; |
399 | | unsigned getExpansionColumnNumber(bool *Invalid = nullptr) const; |
400 | | |
401 | | unsigned getSpellingLineNumber(bool *Invalid = nullptr) const; |
402 | | unsigned getSpellingColumnNumber(bool *Invalid = nullptr) const; |
403 | | |
404 | | const char *getCharacterData(bool *Invalid = nullptr) const; |
405 | | |
406 | | unsigned getLineNumber(bool *Invalid = nullptr) const; |
407 | | unsigned getColumnNumber(bool *Invalid = nullptr) const; |
408 | | |
409 | | const FileEntry *getFileEntry() const; |
410 | | |
411 | | /// Return a StringRef to the source buffer data for the |
412 | | /// specified FileID. |
413 | | StringRef getBufferData(bool *Invalid = nullptr) const; |
414 | | |
415 | | /// Decompose the specified location into a raw FileID + Offset pair. |
416 | | /// |
417 | | /// The first element is the FileID, the second is the offset from the |
418 | | /// start of the buffer of the location. |
419 | | std::pair<FileID, unsigned> getDecomposedLoc() const; |
420 | | |
421 | | bool isInSystemHeader() const; |
422 | | |
423 | | /// Determines the order of 2 source locations in the translation unit. |
424 | | /// |
425 | | /// \returns true if this source location comes before 'Loc', false otherwise. |
426 | | bool isBeforeInTranslationUnitThan(SourceLocation Loc) const; |
427 | | |
428 | | /// Determines the order of 2 source locations in the translation unit. |
429 | | /// |
430 | | /// \returns true if this source location comes before 'Loc', false otherwise. |
431 | 212k | bool isBeforeInTranslationUnitThan(FullSourceLoc Loc) const { |
432 | 212k | assert(Loc.isValid()); |
433 | 0 | assert(SrcMgr == Loc.SrcMgr && "Loc comes from another SourceManager!"); |
434 | 0 | return isBeforeInTranslationUnitThan((SourceLocation)Loc); |
435 | 212k | } |
436 | | |
437 | | /// Comparison function class, useful for sorting FullSourceLocs. |
438 | | struct BeforeThanCompare { |
439 | 7.60k | bool operator()(const FullSourceLoc& lhs, const FullSourceLoc& rhs) const { |
440 | 7.60k | return lhs.isBeforeInTranslationUnitThan(rhs); |
441 | 7.60k | } |
442 | | }; |
443 | | |
444 | | /// Prints information about this FullSourceLoc to stderr. |
445 | | /// |
446 | | /// This is useful for debugging. |
447 | | void dump() const; |
448 | | |
449 | | friend bool |
450 | 205k | operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { |
451 | 205k | return LHS.getRawEncoding() == RHS.getRawEncoding() && |
452 | 205k | LHS.SrcMgr == RHS.SrcMgr2.87k ; |
453 | 205k | } |
454 | | |
455 | | friend bool |
456 | 201k | operator!=(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { |
457 | 201k | return !(LHS == RHS); |
458 | 201k | } |
459 | | }; |
460 | | |
461 | | } // namespace clang |
462 | | |
463 | | namespace llvm { |
464 | | |
465 | | /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and |
466 | | /// DenseSets. |
467 | | template <> |
468 | | struct DenseMapInfo<clang::FileID, void> { |
469 | 59.4M | static clang::FileID getEmptyKey() { |
470 | 59.4M | return {}; |
471 | 59.4M | } |
472 | | |
473 | 52.8M | static clang::FileID getTombstoneKey() { |
474 | 52.8M | return clang::FileID::getSentinel(); |
475 | 52.8M | } |
476 | | |
477 | 52.4M | static unsigned getHashValue(clang::FileID S) { |
478 | 52.4M | return S.getHashValue(); |
479 | 52.4M | } |
480 | | |
481 | 509M | static bool isEqual(clang::FileID LHS, clang::FileID RHS) { |
482 | 509M | return LHS == RHS; |
483 | 509M | } |
484 | | }; |
485 | | |
486 | | /// Define DenseMapInfo so that SourceLocation's can be used as keys in |
487 | | /// DenseMap and DenseSet. This trait class is eqivalent to |
488 | | /// DenseMapInfo<unsigned> which uses SourceLocation::ID is used as a key. |
489 | | template <> struct DenseMapInfo<clang::SourceLocation, void> { |
490 | 333k | static clang::SourceLocation getEmptyKey() { |
491 | 333k | constexpr clang::SourceLocation::UIntTy Zero = 0; |
492 | 333k | return clang::SourceLocation::getFromRawEncoding(~Zero); |
493 | 333k | } |
494 | | |
495 | 198k | static clang::SourceLocation getTombstoneKey() { |
496 | 198k | constexpr clang::SourceLocation::UIntTy Zero = 0; |
497 | 198k | return clang::SourceLocation::getFromRawEncoding(~Zero - 1); |
498 | 198k | } |
499 | | |
500 | 111k | static unsigned getHashValue(clang::SourceLocation Loc) { |
501 | 111k | return Loc.getHashValue(); |
502 | 111k | } |
503 | | |
504 | 3.39M | static bool isEqual(clang::SourceLocation LHS, clang::SourceLocation RHS) { |
505 | 3.39M | return LHS == RHS; |
506 | 3.39M | } |
507 | | }; |
508 | | |
509 | | // Allow calling FoldingSetNodeID::Add with SourceLocation object as parameter |
510 | | template <> struct FoldingSetTrait<clang::SourceLocation, void> { |
511 | | static void Profile(const clang::SourceLocation &X, FoldingSetNodeID &ID); |
512 | | }; |
513 | | |
514 | | } // namespace llvm |
515 | | |
516 | | #endif // LLVM_CLANG_BASIC_SOURCELOCATION_H |