CXSourceLocation.cpp revision d9b877765cfbedc7cb1ee4b50aeb576a46d0df4e
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 "CXLoadedDiagnostic.h"
17#include "CXSourceLocation.h"
18#include "CXString.h"
19#include "CXTranslationUnit.h"
20
21using namespace clang;
22using namespace clang::cxstring;
23
24//===----------------------------------------------------------------------===//
25// Internal predicates on CXSourceLocations.
26//===----------------------------------------------------------------------===//
27
28static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
29  // If the lowest bit is clear then the first ptr_data entry is a SourceManager
30  // pointer, or the CXSourceLocation is a null location.
31  return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
32}
33
34//===----------------------------------------------------------------------===//
35// Basic construction and comparison of CXSourceLocations and CXSourceRanges.
36//===----------------------------------------------------------------------===//
37
38extern "C" {
39
40CXSourceLocation clang_getNullLocation() {
41  CXSourceLocation Result = { { 0, 0 }, 0 };
42  return Result;
43}
44
45unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
46  return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
47          loc1.ptr_data[1] == loc2.ptr_data[1] &&
48          loc1.int_data == loc2.int_data);
49}
50
51CXSourceRange clang_getNullRange() {
52  CXSourceRange Result = { { 0, 0 }, 0, 0 };
53  return Result;
54}
55
56CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
57  if (!isASTUnitSourceLocation(begin)) {
58    if (isASTUnitSourceLocation(end))
59      return clang_getNullRange();
60    CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
61    return Result;
62  }
63
64  if (begin.ptr_data[0] != end.ptr_data[0] ||
65      begin.ptr_data[1] != end.ptr_data[1])
66    return clang_getNullRange();
67
68  CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
69                           begin.int_data, end.int_data };
70
71  return Result;
72}
73
74unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
75  return range1.ptr_data[0] == range2.ptr_data[0]
76    && range1.ptr_data[1] == range2.ptr_data[1]
77    && range1.begin_int_data == range2.begin_int_data
78    && range1.end_int_data == range2.end_int_data;
79}
80
81int clang_Range_isNull(CXSourceRange range) {
82  return clang_equalRanges(range, clang_getNullRange());
83}
84
85
86CXSourceLocation clang_getRangeStart(CXSourceRange range) {
87  // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
88  if ((uintptr_t)range.ptr_data[0] & 0x1) {
89    CXSourceLocation Result = { { range.ptr_data[0], 0 }, 0 };
90    return Result;
91  }
92
93  CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
94    range.begin_int_data };
95  return Result;
96}
97
98CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
99  // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
100  if ((uintptr_t)range.ptr_data[0] & 0x1) {
101    CXSourceLocation Result = { { range.ptr_data[1], 0 }, 0 };
102    return Result;
103  }
104
105  CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
106    range.end_int_data };
107  return Result;
108}
109
110} // end extern "C"
111
112//===----------------------------------------------------------------------===//
113//  Getting CXSourceLocations and CXSourceRanges from a translation unit.
114//===----------------------------------------------------------------------===//
115
116extern "C" {
117
118CXSourceLocation clang_getLocation(CXTranslationUnit tu,
119                                   CXFile file,
120                                   unsigned line,
121                                   unsigned column) {
122  if (!tu || !file)
123    return clang_getNullLocation();
124
125  bool Logging = ::getenv("LIBCLANG_LOGGING");
126  ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
127  ASTUnit::ConcurrencyCheck Check(*CXXUnit);
128  const FileEntry *File = static_cast<const FileEntry *>(file);
129  SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
130  if (SLoc.isInvalid()) {
131    if (Logging)
132      llvm::errs() << "clang_getLocation(\"" << File->getName()
133      << "\", " << line << ", " << column << ") = invalid\n";
134    return clang_getNullLocation();
135  }
136
137  if (Logging)
138    llvm::errs() << "clang_getLocation(\"" << File->getName()
139    << "\", " << line << ", " << column << ") = "
140    << SLoc.getRawEncoding() << "\n";
141
142  return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
143}
144
145CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
146                                            CXFile file,
147                                            unsigned offset) {
148  if (!tu || !file)
149    return clang_getNullLocation();
150
151  ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
152
153  SourceLocation SLoc
154    = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
155
156  if (SLoc.isInvalid())
157    return clang_getNullLocation();
158
159  return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
160}
161
162} // end extern "C"
163
164//===----------------------------------------------------------------------===//
165// Routines for expanding and manipulating CXSourceLocations, regardless
166// of their origin.
167//===----------------------------------------------------------------------===//
168
169static void createNullLocation(CXFile *file, unsigned *line,
170                               unsigned *column, unsigned *offset) {
171  if (file)
172    *file = 0;
173  if (line)
174    *line = 0;
175  if (column)
176    *column = 0;
177  if (offset)
178    *offset = 0;
179  return;
180}
181
182static void createNullLocation(CXString *filename, unsigned *line,
183                               unsigned *column, unsigned *offset = 0) {
184  if (filename)
185    *filename = createCXString("");
186  if (line)
187    *line = 0;
188  if (column)
189    *column = 0;
190  if (offset)
191    *offset = 0;
192  return;
193}
194
195extern "C" {
196
197void clang_getExpansionLocation(CXSourceLocation location,
198                                CXFile *file,
199                                unsigned *line,
200                                unsigned *column,
201                                unsigned *offset) {
202
203  if (!isASTUnitSourceLocation(location)) {
204    CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
205    return;
206  }
207
208  SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
209
210  if (!location.ptr_data[0] || Loc.isInvalid()) {
211    createNullLocation(file, line, column, offset);
212    return;
213  }
214
215  const SourceManager &SM =
216  *static_cast<const SourceManager*>(location.ptr_data[0]);
217  SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
218
219  // Check that the FileID is invalid on the expansion location.
220  // This can manifest in invalid code.
221  FileID fileID = SM.getFileID(ExpansionLoc);
222  bool Invalid = false;
223  const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
224  if (Invalid || !sloc.isFile()) {
225    createNullLocation(file, line, column, offset);
226    return;
227  }
228
229  if (file)
230    *file = (void *)SM.getFileEntryForSLocEntry(sloc);
231  if (line)
232    *line = SM.getExpansionLineNumber(ExpansionLoc);
233  if (column)
234    *column = SM.getExpansionColumnNumber(ExpansionLoc);
235  if (offset)
236    *offset = SM.getDecomposedLoc(ExpansionLoc).second;
237}
238
239void clang_getPresumedLocation(CXSourceLocation location,
240                               CXString *filename,
241                               unsigned *line,
242                               unsigned *column) {
243
244  if (!isASTUnitSourceLocation(location)) {
245    // Other SourceLocation implementations do not support presumed locations
246    // at this time.
247    createNullLocation(filename, line, column);
248    return;
249  }
250
251  SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
252
253  if (!location.ptr_data[0] || Loc.isInvalid())
254    createNullLocation(filename, line, column);
255  else {
256    const SourceManager &SM =
257    *static_cast<const SourceManager*>(location.ptr_data[0]);
258    PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
259
260    if (filename)
261      *filename = createCXString(PreLoc.getFilename());
262    if (line)
263      *line = PreLoc.getLine();
264    if (column)
265      *column = PreLoc.getColumn();
266  }
267}
268
269void clang_getInstantiationLocation(CXSourceLocation location,
270                                    CXFile *file,
271                                    unsigned *line,
272                                    unsigned *column,
273                                    unsigned *offset) {
274  // Redirect to new API.
275  clang_getExpansionLocation(location, file, line, column, offset);
276}
277
278void clang_getSpellingLocation(CXSourceLocation location,
279                               CXFile *file,
280                               unsigned *line,
281                               unsigned *column,
282                               unsigned *offset) {
283
284  if (!isASTUnitSourceLocation(location)) {
285    CXLoadedDiagnostic::decodeLocation(location, file, line,
286                                           column, offset);
287    return;
288  }
289
290  SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
291
292  if (!location.ptr_data[0] || Loc.isInvalid())
293    return createNullLocation(file, line, column, offset);
294
295  const SourceManager &SM =
296  *static_cast<const SourceManager*>(location.ptr_data[0]);
297  SourceLocation SpellLoc = Loc;
298
299  // Unravel the macro instantiation stack.  This logic mirrors that
300  // in DiagnosticRenderer.
301  while (SpellLoc.isMacroID()) {
302    SpellLoc = SM.getImmediateMacroCallerLoc(SpellLoc);
303  }
304
305  std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
306  FileID FID = LocInfo.first;
307  unsigned FileOffset = LocInfo.second;
308
309  if (FID.isInvalid())
310    return createNullLocation(file, line, column, offset);
311
312  if (file)
313    *file = (void *)SM.getFileEntryForID(FID);
314  if (line)
315    *line = SM.getLineNumber(FID, FileOffset);
316  if (column)
317    *column = SM.getColumnNumber(FID, FileOffset);
318  if (offset)
319    *offset = FileOffset;
320}
321
322} // end extern "C"
323
324