xref: /minix3/external/bsd/llvm/dist/clang/tools/libclang/CXSourceLocation.cpp (revision f4a2713ac843a11c696ec80c0a5e3e5d80b4d338)
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 extern "C" {
42 
43 CXSourceLocation clang_getNullLocation() {
44   CXSourceLocation Result = { { 0, 0 }, 0 };
45   return Result;
46 }
47 
48 unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
49   return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
50           loc1.ptr_data[1] == loc2.ptr_data[1] &&
51           loc1.int_data == loc2.int_data);
52 }
53 
54 CXSourceRange clang_getNullRange() {
55   CXSourceRange Result = { { 0, 0 }, 0, 0 };
56   return Result;
57 }
58 
59 CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
60   if (!isASTUnitSourceLocation(begin)) {
61     if (isASTUnitSourceLocation(end))
62       return clang_getNullRange();
63     CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
64     return Result;
65   }
66 
67   if (begin.ptr_data[0] != end.ptr_data[0] ||
68       begin.ptr_data[1] != end.ptr_data[1])
69     return clang_getNullRange();
70 
71   CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
72                            begin.int_data, end.int_data };
73 
74   return Result;
75 }
76 
77 unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
78   return range1.ptr_data[0] == range2.ptr_data[0]
79     && range1.ptr_data[1] == range2.ptr_data[1]
80     && range1.begin_int_data == range2.begin_int_data
81     && range1.end_int_data == range2.end_int_data;
82 }
83 
84 int clang_Range_isNull(CXSourceRange range) {
85   return clang_equalRanges(range, clang_getNullRange());
86 }
87 
88 
89 CXSourceLocation clang_getRangeStart(CXSourceRange range) {
90   // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
91   if ((uintptr_t)range.ptr_data[0] & 0x1) {
92     CXSourceLocation Result = { { range.ptr_data[0], 0 }, 0 };
93     return Result;
94   }
95 
96   CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
97     range.begin_int_data };
98   return Result;
99 }
100 
101 CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
102   // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
103   if ((uintptr_t)range.ptr_data[0] & 0x1) {
104     CXSourceLocation Result = { { range.ptr_data[1], 0 }, 0 };
105     return Result;
106   }
107 
108   CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
109     range.end_int_data };
110   return Result;
111 }
112 
113 } // end extern "C"
114 
115 //===----------------------------------------------------------------------===//
116 //  Getting CXSourceLocations and CXSourceRanges from a translation unit.
117 //===----------------------------------------------------------------------===//
118 
119 extern "C" {
120 
121 CXSourceLocation clang_getLocation(CXTranslationUnit TU,
122                                    CXFile file,
123                                    unsigned line,
124                                    unsigned column) {
125   if (!TU || !file)
126     return clang_getNullLocation();
127   if (line == 0 || column == 0)
128     return clang_getNullLocation();
129 
130   LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
131   ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
132   ASTUnit::ConcurrencyCheck Check(*CXXUnit);
133   const FileEntry *File = static_cast<const FileEntry *>(file);
134   SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
135   if (SLoc.isInvalid()) {
136     if (Log)
137       *Log << llvm::format("(\"%s\", %d, %d) = invalid",
138                            File->getName(), line, column);
139     return clang_getNullLocation();
140   }
141 
142   CXSourceLocation CXLoc =
143       cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
144   if (Log)
145     *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName(), line, column)
146          << CXLoc;
147 
148   return CXLoc;
149 }
150 
151 CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
152                                             CXFile file,
153                                             unsigned offset) {
154   if (!TU || !file)
155     return clang_getNullLocation();
156 
157   ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
158 
159   SourceLocation SLoc
160     = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
161 
162   if (SLoc.isInvalid())
163     return clang_getNullLocation();
164 
165   return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
166 }
167 
168 } // end extern "C"
169 
170 //===----------------------------------------------------------------------===//
171 // Routines for expanding and manipulating CXSourceLocations, regardless
172 // of their origin.
173 //===----------------------------------------------------------------------===//
174 
175 static void createNullLocation(CXFile *file, unsigned *line,
176                                unsigned *column, unsigned *offset) {
177   if (file)
178     *file = 0;
179   if (line)
180     *line = 0;
181   if (column)
182     *column = 0;
183   if (offset)
184     *offset = 0;
185   return;
186 }
187 
188 static void createNullLocation(CXString *filename, unsigned *line,
189                                unsigned *column, unsigned *offset = 0) {
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   return;
199 }
200 
201 extern "C" {
202 
203 int clang_Location_isInSystemHeader(CXSourceLocation location) {
204   const SourceLocation Loc =
205     SourceLocation::getFromRawEncoding(location.int_data);
206   if (Loc.isInvalid())
207     return 0;
208 
209   const SourceManager &SM =
210     *static_cast<const SourceManager*>(location.ptr_data[0]);
211   return SM.isInSystemHeader(Loc);
212 }
213 
214 int clang_Location_isFromMainFile(CXSourceLocation location) {
215   const SourceLocation Loc =
216     SourceLocation::getFromRawEncoding(location.int_data);
217   if (Loc.isInvalid())
218     return 0;
219 
220   const SourceManager &SM =
221     *static_cast<const SourceManager*>(location.ptr_data[0]);
222   return SM.isWrittenInMainFile(Loc);
223 }
224 
225 void clang_getExpansionLocation(CXSourceLocation location,
226                                 CXFile *file,
227                                 unsigned *line,
228                                 unsigned *column,
229                                 unsigned *offset) {
230 
231   if (!isASTUnitSourceLocation(location)) {
232     CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
233     return;
234   }
235 
236   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
237 
238   if (!location.ptr_data[0] || Loc.isInvalid()) {
239     createNullLocation(file, line, column, offset);
240     return;
241   }
242 
243   const SourceManager &SM =
244   *static_cast<const SourceManager*>(location.ptr_data[0]);
245   SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
246 
247   // Check that the FileID is invalid on the expansion location.
248   // This can manifest in invalid code.
249   FileID fileID = SM.getFileID(ExpansionLoc);
250   bool Invalid = false;
251   const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
252   if (Invalid || !sloc.isFile()) {
253     createNullLocation(file, line, column, offset);
254     return;
255   }
256 
257   if (file)
258     *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
259   if (line)
260     *line = SM.getExpansionLineNumber(ExpansionLoc);
261   if (column)
262     *column = SM.getExpansionColumnNumber(ExpansionLoc);
263   if (offset)
264     *offset = SM.getDecomposedLoc(ExpansionLoc).second;
265 }
266 
267 void clang_getPresumedLocation(CXSourceLocation location,
268                                CXString *filename,
269                                unsigned *line,
270                                unsigned *column) {
271 
272   if (!isASTUnitSourceLocation(location)) {
273     // Other SourceLocation implementations do not support presumed locations
274     // at this time.
275     createNullLocation(filename, line, column);
276     return;
277   }
278 
279   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
280 
281   if (!location.ptr_data[0] || Loc.isInvalid()) {
282     createNullLocation(filename, line, column);
283     return;
284   }
285 
286   const SourceManager &SM =
287       *static_cast<const SourceManager *>(location.ptr_data[0]);
288   PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
289   if (PreLoc.isInvalid()) {
290     createNullLocation(filename, line, column);
291     return;
292   }
293 
294   if (filename) *filename = cxstring::createRef(PreLoc.getFilename());
295   if (line) *line = PreLoc.getLine();
296   if (column) *column = PreLoc.getColumn();
297 }
298 
299 void clang_getInstantiationLocation(CXSourceLocation location,
300                                     CXFile *file,
301                                     unsigned *line,
302                                     unsigned *column,
303                                     unsigned *offset) {
304   // Redirect to new API.
305   clang_getExpansionLocation(location, file, line, column, offset);
306 }
307 
308 void clang_getSpellingLocation(CXSourceLocation location,
309                                CXFile *file,
310                                unsigned *line,
311                                unsigned *column,
312                                unsigned *offset) {
313 
314   if (!isASTUnitSourceLocation(location)) {
315     CXLoadedDiagnostic::decodeLocation(location, file, line,
316                                            column, offset);
317     return;
318   }
319 
320   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
321 
322   if (!location.ptr_data[0] || Loc.isInvalid())
323     return createNullLocation(file, line, column, offset);
324 
325   const SourceManager &SM =
326   *static_cast<const SourceManager*>(location.ptr_data[0]);
327   // FIXME: This should call SourceManager::getSpellingLoc().
328   SourceLocation SpellLoc = SM.getFileLoc(Loc);
329   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
330   FileID FID = LocInfo.first;
331   unsigned FileOffset = LocInfo.second;
332 
333   if (FID.isInvalid())
334     return createNullLocation(file, line, column, offset);
335 
336   if (file)
337     *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
338   if (line)
339     *line = SM.getLineNumber(FID, FileOffset);
340   if (column)
341     *column = SM.getColumnNumber(FID, FileOffset);
342   if (offset)
343     *offset = FileOffset;
344 }
345 
346 void clang_getFileLocation(CXSourceLocation location,
347                            CXFile *file,
348                            unsigned *line,
349                            unsigned *column,
350                            unsigned *offset) {
351 
352   if (!isASTUnitSourceLocation(location)) {
353     CXLoadedDiagnostic::decodeLocation(location, file, line,
354                                            column, offset);
355     return;
356   }
357 
358   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
359 
360   if (!location.ptr_data[0] || Loc.isInvalid())
361     return createNullLocation(file, line, column, offset);
362 
363   const SourceManager &SM =
364   *static_cast<const SourceManager*>(location.ptr_data[0]);
365   SourceLocation FileLoc = SM.getFileLoc(Loc);
366   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
367   FileID FID = LocInfo.first;
368   unsigned FileOffset = LocInfo.second;
369 
370   if (FID.isInvalid())
371     return createNullLocation(file, line, column, offset);
372 
373   if (file)
374     *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
375   if (line)
376     *line = SM.getLineNumber(FID, FileOffset);
377   if (column)
378     *column = SM.getColumnNumber(FID, FileOffset);
379   if (offset)
380     *offset = FileOffset;
381 }
382 
383 } // end extern "C"
384