• 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