]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/libclang/CXSourceLocation.cpp
Vendor import of clang trunk r290819:
[FreeBSD/FreeBSD.git] / tools / libclang / CXSourceLocation.cpp
1 //===- CXSourceLocation.cpp - CXSourceLocations APIs ------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines routines for manipulating CXSourceLocations.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "clang/Frontend/ASTUnit.h"
15 #include "CIndexer.h"
16 #include "CLog.h"
17 #include "CXLoadedDiagnostic.h"
18 #include "CXSourceLocation.h"
19 #include "CXString.h"
20 #include "CXTranslationUnit.h"
21 #include "llvm/Support/Compiler.h"
22 #include "llvm/Support/Format.h"
23
24 using namespace clang;
25 using namespace clang::cxindex;
26
27 //===----------------------------------------------------------------------===//
28 // Internal predicates on CXSourceLocations.
29 //===----------------------------------------------------------------------===//
30
31 static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
32   // If the lowest bit is clear then the first ptr_data entry is a SourceManager
33   // pointer, or the CXSourceLocation is a null location.
34   return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
35 }
36
37 //===----------------------------------------------------------------------===//
38 // Basic construction and comparison of CXSourceLocations and CXSourceRanges.
39 //===----------------------------------------------------------------------===//
40
41 CXSourceLocation clang_getNullLocation() {
42   CXSourceLocation Result = { { nullptr, nullptr }, 0 };
43   return Result;
44 }
45
46 unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
47   return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
48           loc1.ptr_data[1] == loc2.ptr_data[1] &&
49           loc1.int_data == loc2.int_data);
50 }
51
52 CXSourceRange clang_getNullRange() {
53   CXSourceRange Result = { { nullptr, nullptr }, 0, 0 };
54   return Result;
55 }
56
57 CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
58   if (!isASTUnitSourceLocation(begin)) {
59     if (isASTUnitSourceLocation(end))
60       return clang_getNullRange();
61     CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
62     return Result;
63   }
64   
65   if (begin.ptr_data[0] != end.ptr_data[0] ||
66       begin.ptr_data[1] != end.ptr_data[1])
67     return clang_getNullRange();
68   
69   CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
70                            begin.int_data, end.int_data };
71
72   return Result;
73 }
74
75 unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
76   return range1.ptr_data[0] == range2.ptr_data[0]
77     && range1.ptr_data[1] == range2.ptr_data[1]
78     && range1.begin_int_data == range2.begin_int_data
79     && range1.end_int_data == range2.end_int_data;
80 }
81
82 int clang_Range_isNull(CXSourceRange range) {
83   return clang_equalRanges(range, clang_getNullRange());
84 }
85   
86   
87 CXSourceLocation clang_getRangeStart(CXSourceRange range) {
88   // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
89   if ((uintptr_t)range.ptr_data[0] & 0x1) {
90     CXSourceLocation Result = { { range.ptr_data[0], nullptr }, 0 };
91     return Result;    
92   }
93   
94   CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
95     range.begin_int_data };
96   return Result;
97 }
98
99 CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
100   // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
101   if ((uintptr_t)range.ptr_data[0] & 0x1) {
102     CXSourceLocation Result = { { range.ptr_data[1], nullptr }, 0 };
103     return Result;    
104   }
105
106   CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
107     range.end_int_data };
108   return Result;
109 }
110
111 //===----------------------------------------------------------------------===//
112 //  Getting CXSourceLocations and CXSourceRanges from a translation unit.
113 //===----------------------------------------------------------------------===//
114
115 CXSourceLocation clang_getLocation(CXTranslationUnit TU,
116                                    CXFile file,
117                                    unsigned line,
118                                    unsigned column) {
119   if (cxtu::isNotUsableTU(TU)) {
120     LOG_BAD_TU(TU);
121     return clang_getNullLocation();
122   }
123   if (!file)
124     return clang_getNullLocation();
125   if (line == 0 || column == 0)
126     return clang_getNullLocation();
127   
128   LogRef Log = Logger::make(__func__);
129   ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
130   ASTUnit::ConcurrencyCheck Check(*CXXUnit);
131   const FileEntry *File = static_cast<const FileEntry *>(file);
132   SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
133   if (SLoc.isInvalid()) {
134     if (Log)
135       *Log << llvm::format("(\"%s\", %d, %d) = invalid",
136                            File->getName().str().c_str(), line, column);
137     return clang_getNullLocation();
138   }
139   
140   CXSourceLocation CXLoc =
141       cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
142   if (Log)
143     *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName().str().c_str(),
144                          line, column)
145          << CXLoc;
146
147   return CXLoc;
148 }
149   
150 CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
151                                             CXFile file,
152                                             unsigned offset) {
153   if (cxtu::isNotUsableTU(TU)) {
154     LOG_BAD_TU(TU);
155     return clang_getNullLocation();
156   }
157   if (!file)
158     return clang_getNullLocation();
159
160   ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
161
162   SourceLocation SLoc 
163     = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
164
165   if (SLoc.isInvalid())
166     return clang_getNullLocation();
167   
168   return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
169 }
170
171 //===----------------------------------------------------------------------===//
172 // Routines for expanding and manipulating CXSourceLocations, regardless
173 // of their origin.
174 //===----------------------------------------------------------------------===//
175
176 static void createNullLocation(CXFile *file, unsigned *line,
177                                unsigned *column, unsigned *offset) {
178   if (file)
179     *file = nullptr;
180   if (line)
181     *line = 0;
182   if (column)
183     *column = 0;
184   if (offset)
185     *offset = 0;
186 }
187
188 static void createNullLocation(CXString *filename, unsigned *line,
189                                unsigned *column, unsigned *offset = nullptr) {
190   if (filename)
191     *filename = cxstring::createEmpty();
192   if (line)
193     *line = 0;
194   if (column)
195     *column = 0;
196   if (offset)
197     *offset = 0;
198 }
199
200 int clang_Location_isInSystemHeader(CXSourceLocation location) {
201   const SourceLocation Loc =
202     SourceLocation::getFromRawEncoding(location.int_data);
203   if (Loc.isInvalid())
204     return 0;
205
206   const SourceManager &SM =
207     *static_cast<const SourceManager*>(location.ptr_data[0]);
208   return SM.isInSystemHeader(Loc);
209 }
210
211 int clang_Location_isFromMainFile(CXSourceLocation location) {
212   const SourceLocation Loc =
213     SourceLocation::getFromRawEncoding(location.int_data);
214   if (Loc.isInvalid())
215     return 0;
216
217   const SourceManager &SM =
218     *static_cast<const SourceManager*>(location.ptr_data[0]);
219   return SM.isWrittenInMainFile(Loc);
220 }
221
222 void clang_getExpansionLocation(CXSourceLocation location,
223                                 CXFile *file,
224                                 unsigned *line,
225                                 unsigned *column,
226                                 unsigned *offset) {
227   if (!isASTUnitSourceLocation(location)) {
228     CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
229     return;
230   }
231
232   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
233
234   if (!location.ptr_data[0] || Loc.isInvalid()) {
235     createNullLocation(file, line, column, offset);
236     return;
237   }
238
239   const SourceManager &SM =
240   *static_cast<const SourceManager*>(location.ptr_data[0]);
241   SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
242   
243   // Check that the FileID is invalid on the expansion location.
244   // This can manifest in invalid code.
245   FileID fileID = SM.getFileID(ExpansionLoc);
246   bool Invalid = false;
247   const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
248   if (Invalid || !sloc.isFile()) {
249     createNullLocation(file, line, column, offset);
250     return;
251   }
252   
253   if (file)
254     *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
255   if (line)
256     *line = SM.getExpansionLineNumber(ExpansionLoc);
257   if (column)
258     *column = SM.getExpansionColumnNumber(ExpansionLoc);
259   if (offset)
260     *offset = SM.getDecomposedLoc(ExpansionLoc).second;
261 }
262
263 void clang_getPresumedLocation(CXSourceLocation location,
264                                CXString *filename,
265                                unsigned *line,
266                                unsigned *column) {
267   if (!isASTUnitSourceLocation(location)) {
268     // Other SourceLocation implementations do not support presumed locations
269     // at this time.
270     createNullLocation(filename, line, column);
271     return;
272   }
273
274   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
275
276   if (!location.ptr_data[0] || Loc.isInvalid()) {
277     createNullLocation(filename, line, column);
278     return;
279   }
280
281   const SourceManager &SM =
282       *static_cast<const SourceManager *>(location.ptr_data[0]);
283   PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
284   if (PreLoc.isInvalid()) {
285     createNullLocation(filename, line, column);
286     return;
287   }
288
289   if (filename) *filename = cxstring::createRef(PreLoc.getFilename());
290   if (line) *line = PreLoc.getLine();
291   if (column) *column = PreLoc.getColumn();
292 }
293
294 void clang_getInstantiationLocation(CXSourceLocation location,
295                                     CXFile *file,
296                                     unsigned *line,
297                                     unsigned *column,
298                                     unsigned *offset) {
299   // Redirect to new API.
300   clang_getExpansionLocation(location, file, line, column, offset);
301 }
302
303 void clang_getSpellingLocation(CXSourceLocation location,
304                                CXFile *file,
305                                unsigned *line,
306                                unsigned *column,
307                                unsigned *offset) {
308   if (!isASTUnitSourceLocation(location)) {
309     CXLoadedDiagnostic::decodeLocation(location, file, line,
310                                            column, offset);
311     return;
312   }
313   
314   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
315   
316   if (!location.ptr_data[0] || Loc.isInvalid())
317     return createNullLocation(file, line, column, offset);
318   
319   const SourceManager &SM =
320   *static_cast<const SourceManager*>(location.ptr_data[0]);
321   // FIXME: This should call SourceManager::getSpellingLoc().
322   SourceLocation SpellLoc = SM.getFileLoc(Loc);
323   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
324   FileID FID = LocInfo.first;
325   unsigned FileOffset = LocInfo.second;
326   
327   if (FID.isInvalid())
328     return createNullLocation(file, line, column, offset);
329   
330   if (file)
331     *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
332   if (line)
333     *line = SM.getLineNumber(FID, FileOffset);
334   if (column)
335     *column = SM.getColumnNumber(FID, FileOffset);
336   if (offset)
337     *offset = FileOffset;
338 }
339
340 void clang_getFileLocation(CXSourceLocation location,
341                            CXFile *file,
342                            unsigned *line,
343                            unsigned *column,
344                            unsigned *offset) {
345   if (!isASTUnitSourceLocation(location)) {
346     CXLoadedDiagnostic::decodeLocation(location, file, line,
347                                            column, offset);
348     return;
349   }
350
351   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
352
353   if (!location.ptr_data[0] || Loc.isInvalid())
354     return createNullLocation(file, line, column, offset);
355
356   const SourceManager &SM =
357   *static_cast<const SourceManager*>(location.ptr_data[0]);
358   SourceLocation FileLoc = SM.getFileLoc(Loc);
359   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
360   FileID FID = LocInfo.first;
361   unsigned FileOffset = LocInfo.second;
362
363   if (FID.isInvalid())
364     return createNullLocation(file, line, column, offset);
365
366   if (file)
367     *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
368   if (line)
369     *line = SM.getLineNumber(FID, FileOffset);
370   if (column)
371     *column = SM.getColumnNumber(FID, FileOffset);
372   if (offset)
373     *offset = FileOffset;
374 }