• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
isASTUnitSourceLocation(const CXSourceLocation & L)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 
clang_getNullLocation()43 CXSourceLocation clang_getNullLocation() {
44   CXSourceLocation Result = { { 0, 0 }, 0 };
45   return Result;
46 }
47 
clang_equalLocations(CXSourceLocation loc1,CXSourceLocation loc2)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 
clang_getNullRange()54 CXSourceRange clang_getNullRange() {
55   CXSourceRange Result = { { 0, 0 }, 0, 0 };
56   return Result;
57 }
58 
clang_getRange(CXSourceLocation begin,CXSourceLocation end)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 
clang_equalRanges(CXSourceRange range1,CXSourceRange range2)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 
clang_Range_isNull(CXSourceRange range)84 int clang_Range_isNull(CXSourceRange range) {
85   return clang_equalRanges(range, clang_getNullRange());
86 }
87 
88 
clang_getRangeStart(CXSourceRange range)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 
clang_getRangeEnd(CXSourceRange range)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 
clang_getLocation(CXTranslationUnit TU,CXFile file,unsigned line,unsigned column)121 CXSourceLocation clang_getLocation(CXTranslationUnit TU,
122                                    CXFile file,
123                                    unsigned line,
124                                    unsigned column) {
125   if (!TU || !file)
126     return clang_getNullLocation();
127 
128   LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
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(), 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(), line, column)
144          << CXLoc;
145 
146   return CXLoc;
147 }
148 
clang_getLocationForOffset(CXTranslationUnit TU,CXFile file,unsigned offset)149 CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
150                                             CXFile file,
151                                             unsigned offset) {
152   if (!TU || !file)
153     return clang_getNullLocation();
154 
155   ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
156 
157   SourceLocation SLoc
158     = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
159 
160   if (SLoc.isInvalid())
161     return clang_getNullLocation();
162 
163   return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
164 }
165 
166 } // end extern "C"
167 
168 //===----------------------------------------------------------------------===//
169 // Routines for expanding and manipulating CXSourceLocations, regardless
170 // of their origin.
171 //===----------------------------------------------------------------------===//
172 
createNullLocation(CXFile * file,unsigned * line,unsigned * column,unsigned * offset)173 static void createNullLocation(CXFile *file, unsigned *line,
174                                unsigned *column, unsigned *offset) {
175   if (file)
176     *file = 0;
177   if (line)
178     *line = 0;
179   if (column)
180     *column = 0;
181   if (offset)
182     *offset = 0;
183   return;
184 }
185 
createNullLocation(CXString * filename,unsigned * line,unsigned * column,unsigned * offset=0)186 static void createNullLocation(CXString *filename, unsigned *line,
187                                unsigned *column, unsigned *offset = 0) {
188   if (filename)
189     *filename = cxstring::createEmpty();
190   if (line)
191     *line = 0;
192   if (column)
193     *column = 0;
194   if (offset)
195     *offset = 0;
196   return;
197 }
198 
199 extern "C" {
200 
clang_Location_isInSystemHeader(CXSourceLocation location)201 int clang_Location_isInSystemHeader(CXSourceLocation location) {
202   const SourceLocation Loc =
203     SourceLocation::getFromRawEncoding(location.int_data);
204   if (Loc.isInvalid())
205     return 0;
206 
207   const SourceManager &SM =
208     *static_cast<const SourceManager*>(location.ptr_data[0]);
209   return SM.isInSystemHeader(Loc);
210 }
211 
clang_getExpansionLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)212 void clang_getExpansionLocation(CXSourceLocation location,
213                                 CXFile *file,
214                                 unsigned *line,
215                                 unsigned *column,
216                                 unsigned *offset) {
217 
218   if (!isASTUnitSourceLocation(location)) {
219     CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
220     return;
221   }
222 
223   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
224 
225   if (!location.ptr_data[0] || Loc.isInvalid()) {
226     createNullLocation(file, line, column, offset);
227     return;
228   }
229 
230   const SourceManager &SM =
231   *static_cast<const SourceManager*>(location.ptr_data[0]);
232   SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
233 
234   // Check that the FileID is invalid on the expansion location.
235   // This can manifest in invalid code.
236   FileID fileID = SM.getFileID(ExpansionLoc);
237   bool Invalid = false;
238   const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
239   if (Invalid || !sloc.isFile()) {
240     createNullLocation(file, line, column, offset);
241     return;
242   }
243 
244   if (file)
245     *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
246   if (line)
247     *line = SM.getExpansionLineNumber(ExpansionLoc);
248   if (column)
249     *column = SM.getExpansionColumnNumber(ExpansionLoc);
250   if (offset)
251     *offset = SM.getDecomposedLoc(ExpansionLoc).second;
252 }
253 
clang_getPresumedLocation(CXSourceLocation location,CXString * filename,unsigned * line,unsigned * column)254 void clang_getPresumedLocation(CXSourceLocation location,
255                                CXString *filename,
256                                unsigned *line,
257                                unsigned *column) {
258 
259   if (!isASTUnitSourceLocation(location)) {
260     // Other SourceLocation implementations do not support presumed locations
261     // at this time.
262     createNullLocation(filename, line, column);
263     return;
264   }
265 
266   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
267 
268   if (!location.ptr_data[0] || Loc.isInvalid())
269     createNullLocation(filename, line, column);
270   else {
271     const SourceManager &SM =
272     *static_cast<const SourceManager*>(location.ptr_data[0]);
273     PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
274 
275     if (filename)
276       *filename = cxstring::createRef(PreLoc.getFilename());
277     if (line)
278       *line = PreLoc.getLine();
279     if (column)
280       *column = PreLoc.getColumn();
281   }
282 }
283 
clang_getInstantiationLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)284 void clang_getInstantiationLocation(CXSourceLocation location,
285                                     CXFile *file,
286                                     unsigned *line,
287                                     unsigned *column,
288                                     unsigned *offset) {
289   // Redirect to new API.
290   clang_getExpansionLocation(location, file, line, column, offset);
291 }
292 
clang_getSpellingLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)293 void clang_getSpellingLocation(CXSourceLocation location,
294                                CXFile *file,
295                                unsigned *line,
296                                unsigned *column,
297                                unsigned *offset) {
298 
299   if (!isASTUnitSourceLocation(location)) {
300     CXLoadedDiagnostic::decodeLocation(location, file, line,
301                                            column, offset);
302     return;
303   }
304 
305   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
306 
307   if (!location.ptr_data[0] || Loc.isInvalid())
308     return createNullLocation(file, line, column, offset);
309 
310   const SourceManager &SM =
311   *static_cast<const SourceManager*>(location.ptr_data[0]);
312   // FIXME: This should call SourceManager::getSpellingLoc().
313   SourceLocation SpellLoc = SM.getFileLoc(Loc);
314   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
315   FileID FID = LocInfo.first;
316   unsigned FileOffset = LocInfo.second;
317 
318   if (FID.isInvalid())
319     return createNullLocation(file, line, column, offset);
320 
321   if (file)
322     *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
323   if (line)
324     *line = SM.getLineNumber(FID, FileOffset);
325   if (column)
326     *column = SM.getColumnNumber(FID, FileOffset);
327   if (offset)
328     *offset = FileOffset;
329 }
330 
clang_getFileLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)331 void clang_getFileLocation(CXSourceLocation location,
332                            CXFile *file,
333                            unsigned *line,
334                            unsigned *column,
335                            unsigned *offset) {
336 
337   if (!isASTUnitSourceLocation(location)) {
338     CXLoadedDiagnostic::decodeLocation(location, file, line,
339                                            column, offset);
340     return;
341   }
342 
343   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
344 
345   if (!location.ptr_data[0] || Loc.isInvalid())
346     return createNullLocation(file, line, column, offset);
347 
348   const SourceManager &SM =
349   *static_cast<const SourceManager*>(location.ptr_data[0]);
350   SourceLocation FileLoc = SM.getFileLoc(Loc);
351   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
352   FileID FID = LocInfo.first;
353   unsigned FileOffset = LocInfo.second;
354 
355   if (FID.isInvalid())
356     return createNullLocation(file, line, column, offset);
357 
358   if (file)
359     *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
360   if (line)
361     *line = SM.getLineNumber(FID, FileOffset);
362   if (column)
363     *column = SM.getColumnNumber(FID, FileOffset);
364   if (offset)
365     *offset = FileOffset;
366 }
367 
368 } // end extern "C"
369