CXSourceLocation.cpp revision 51a7d5d7f6bf60c562d825bc271fd4cf696b33b5
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
16#include "CIndexer.h"
17#include "CXString.h"
18#include "CXSourceLocation.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 (begin.ptr_data[0] != end.ptr_data[0] ||
58      begin.ptr_data[1] != end.ptr_data[1])
59    return clang_getNullRange();
60
61  CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
62                           begin.int_data, end.int_data };
63
64  return Result;
65}
66
67
68unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
69  return range1.ptr_data[0] == range2.ptr_data[0]
70    && range1.ptr_data[1] == range2.ptr_data[1]
71    && range1.begin_int_data == range2.begin_int_data
72    && range1.end_int_data == range2.end_int_data;
73}
74
75int clang_Range_isNull(CXSourceRange range) {
76  return clang_equalRanges(range, clang_getNullRange());
77}
78
79
80CXSourceLocation clang_getRangeStart(CXSourceRange range) {
81  CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
82    range.begin_int_data };
83  return Result;
84}
85
86CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
87  CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
88    range.end_int_data };
89  return Result;
90}
91
92} // end extern "C"
93
94//===----------------------------------------------------------------------===//
95//  Getting CXSourceLocations and CXSourceRanges from a translation unit.
96//===----------------------------------------------------------------------===//
97
98extern "C" {
99
100CXSourceLocation clang_getLocation(CXTranslationUnit tu,
101                                   CXFile file,
102                                   unsigned line,
103                                   unsigned column) {
104  if (!tu || !file)
105    return clang_getNullLocation();
106
107  bool Logging = ::getenv("LIBCLANG_LOGGING");
108  ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
109  ASTUnit::ConcurrencyCheck Check(*CXXUnit);
110  const FileEntry *File = static_cast<const FileEntry *>(file);
111  SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
112  if (SLoc.isInvalid()) {
113    if (Logging)
114      llvm::errs() << "clang_getLocation(\"" << File->getName()
115      << "\", " << line << ", " << column << ") = invalid\n";
116    return clang_getNullLocation();
117  }
118
119  if (Logging)
120    llvm::errs() << "clang_getLocation(\"" << File->getName()
121    << "\", " << line << ", " << column << ") = "
122    << SLoc.getRawEncoding() << "\n";
123
124  return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
125}
126
127CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
128                                            CXFile file,
129                                            unsigned offset) {
130  if (!tu || !file)
131    return clang_getNullLocation();
132
133  ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
134
135  SourceLocation SLoc
136    = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
137
138  if (SLoc.isInvalid())
139    return clang_getNullLocation();
140
141  return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
142}
143
144} // end extern "C"
145
146//===----------------------------------------------------------------------===//
147// Routines for expanding and manipulating CXSourceLocations, regardless
148// of their origin.
149//===----------------------------------------------------------------------===//
150
151static void createNullLocation(CXFile *file, unsigned *line,
152                               unsigned *column, unsigned *offset) {
153  if (file)
154    *file = 0;
155  if (line)
156    *line = 0;
157  if (column)
158    *column = 0;
159  if (offset)
160    *offset = 0;
161  return;
162}
163
164static void createNullLocation(CXString *filename, unsigned *line,
165                               unsigned *column, unsigned *offset = 0) {
166  if (filename)
167    *filename = createCXString("");
168  if (line)
169    *line = 0;
170  if (column)
171    *column = 0;
172  if (offset)
173    *offset = 0;
174  return;
175}
176
177extern "C" {
178
179void clang_getExpansionLocation(CXSourceLocation location,
180                                CXFile *file,
181                                unsigned *line,
182                                unsigned *column,
183                                unsigned *offset) {
184
185  if (isASTUnitSourceLocation(location)) {
186    SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
187
188    if (!location.ptr_data[0] || Loc.isInvalid()) {
189      createNullLocation(file, line, column, offset);
190      return;
191    }
192
193    const SourceManager &SM =
194    *static_cast<const SourceManager*>(location.ptr_data[0]);
195    SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
196
197    // Check that the FileID is invalid on the expansion location.
198    // This can manifest in invalid code.
199    FileID fileID = SM.getFileID(ExpansionLoc);
200    bool Invalid = false;
201    const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
202    if (Invalid || !sloc.isFile()) {
203      createNullLocation(file, line, column, offset);
204      return;
205    }
206
207    if (file)
208      *file = (void *)SM.getFileEntryForSLocEntry(sloc);
209    if (line)
210      *line = SM.getExpansionLineNumber(ExpansionLoc);
211    if (column)
212      *column = SM.getExpansionColumnNumber(ExpansionLoc);
213    if (offset)
214      *offset = SM.getDecomposedLoc(ExpansionLoc).second;
215  }
216
217  // FIXME:
218  createNullLocation(file, line, column, offset);
219}
220
221void clang_getPresumedLocation(CXSourceLocation location,
222                               CXString *filename,
223                               unsigned *line,
224                               unsigned *column) {
225
226  if (isASTUnitSourceLocation(location)) {
227    SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
228
229    if (!location.ptr_data[0] || Loc.isInvalid())
230      createNullLocation(filename, line, column);
231    else {
232      const SourceManager &SM =
233      *static_cast<const SourceManager*>(location.ptr_data[0]);
234      PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
235
236      if (filename)
237        *filename = createCXString(PreLoc.getFilename());
238      if (line)
239        *line = PreLoc.getLine();
240      if (column)
241        *column = PreLoc.getColumn();
242    }
243    return;
244  }
245
246  // FIXME:
247  createNullLocation(filename, line, column);
248}
249
250void clang_getInstantiationLocation(CXSourceLocation location,
251                                    CXFile *file,
252                                    unsigned *line,
253                                    unsigned *column,
254                                    unsigned *offset) {
255  // Redirect to new API.
256  clang_getExpansionLocation(location, file, line, column, offset);
257}
258
259void clang_getSpellingLocation(CXSourceLocation location,
260                               CXFile *file,
261                               unsigned *line,
262                               unsigned *column,
263                               unsigned *offset) {
264
265  if (isASTUnitSourceLocation(location)) {
266    SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
267
268    if (!location.ptr_data[0] || Loc.isInvalid())
269      return createNullLocation(file, line, column, offset);
270
271    const SourceManager &SM =
272    *static_cast<const SourceManager*>(location.ptr_data[0]);
273    SourceLocation SpellLoc = Loc;
274    if (SpellLoc.isMacroID()) {
275      SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc);
276      if (SimpleSpellingLoc.isFileID() &&
277          SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first))
278        SpellLoc = SimpleSpellingLoc;
279      else
280        SpellLoc = SM.getExpansionLoc(SpellLoc);
281    }
282
283    std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
284    FileID FID = LocInfo.first;
285    unsigned FileOffset = LocInfo.second;
286
287    if (FID.isInvalid())
288      return createNullLocation(file, line, column, offset);
289
290    if (file)
291      *file = (void *)SM.getFileEntryForID(FID);
292    if (line)
293      *line = SM.getLineNumber(FID, FileOffset);
294    if (column)
295      *column = SM.getColumnNumber(FID, FileOffset);
296    if (offset)
297      *offset = FileOffset;
298    return;
299  }
300
301  // FIXME:
302  createNullLocation(file, line, column, offset);
303}
304
305} // end extern "C"
306
307