CXSourceLocation.cpp revision 8644aa9149f40fb00bfd20f0a22a873428f520d3
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
24using namespace clang;
25using namespace clang::cxindex;
26
27//===----------------------------------------------------------------------===//
28// Internal predicates on CXSourceLocations.
29//===----------------------------------------------------------------------===//
30
31static 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
41extern "C" {
42
43CXSourceLocation clang_getNullLocation() {
44  CXSourceLocation Result = { { 0, 0 }, 0 };
45  return Result;
46}
47
48unsigned 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
54CXSourceRange clang_getNullRange() {
55  CXSourceRange Result = { { 0, 0 }, 0, 0 };
56  return Result;
57}
58
59CXSourceRange 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
77unsigned 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
84int clang_Range_isNull(CXSourceRange range) {
85  return clang_equalRanges(range, clang_getNullRange());
86}
87
88
89CXSourceLocation 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
101CXSourceLocation 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
119extern "C" {
120
121CXSourceLocation 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
151CXSourceLocation 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
175static 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
188static 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
201extern "C" {
202
203int 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
214int 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
225void 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
267void 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
299void 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
308void 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
346void 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