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 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 43 CXSourceLocation clang_getNullLocation() { 44 CXSourceLocation Result = { { 0, 0 }, 0 }; 45 return Result; 46 } 47 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 54 CXSourceRange clang_getNullRange() { 55 CXSourceRange Result = { { 0, 0 }, 0, 0 }; 56 return Result; 57 } 58 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 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 84 int clang_Range_isNull(CXSourceRange range) { 85 return clang_equalRanges(range, clang_getNullRange()); 86 } 87 88 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 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 121 CXSourceLocation 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 151 CXSourceLocation 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 175 static 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 188 static 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 201 extern "C" { 202 203 int 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 214 int 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 225 void 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 267 void 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 299 void 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 308 void 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 346 void 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