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