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 = { { nullptr, nullptr }, 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 = { { nullptr, nullptr }, 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], nullptr }, 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], nullptr }, 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 (cxtu::isNotUsableTU(TU)) { 126 LOG_BAD_TU(TU); 127 return clang_getNullLocation(); 128 } 129 if (!file) 130 return clang_getNullLocation(); 131 if (line == 0 || column == 0) 132 return clang_getNullLocation(); 133 134 LogRef Log = Logger::make(LLVM_FUNCTION_NAME); 135 ASTUnit *CXXUnit = cxtu::getASTUnit(TU); 136 ASTUnit::ConcurrencyCheck Check(*CXXUnit); 137 const FileEntry *File = static_cast<const FileEntry *>(file); 138 SourceLocation SLoc = CXXUnit->getLocation(File, line, column); 139 if (SLoc.isInvalid()) { 140 if (Log) 141 *Log << llvm::format("(\"%s\", %d, %d) = invalid", 142 File->getName(), line, column); 143 return clang_getNullLocation(); 144 } 145 146 CXSourceLocation CXLoc = 147 cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); 148 if (Log) 149 *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName(), line, column) 150 << CXLoc; 151 152 return CXLoc; 153 } 154 155 CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU, 156 CXFile file, 157 unsigned offset) { 158 if (cxtu::isNotUsableTU(TU)) { 159 LOG_BAD_TU(TU); 160 return clang_getNullLocation(); 161 } 162 if (!file) 163 return clang_getNullLocation(); 164 165 ASTUnit *CXXUnit = cxtu::getASTUnit(TU); 166 167 SourceLocation SLoc 168 = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset); 169 170 if (SLoc.isInvalid()) 171 return clang_getNullLocation(); 172 173 return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); 174 } 175 176 } // end extern "C" 177 178 //===----------------------------------------------------------------------===// 179 // Routines for expanding and manipulating CXSourceLocations, regardless 180 // of their origin. 181 //===----------------------------------------------------------------------===// 182 183 static void createNullLocation(CXFile *file, unsigned *line, 184 unsigned *column, unsigned *offset) { 185 if (file) 186 *file = nullptr; 187 if (line) 188 *line = 0; 189 if (column) 190 *column = 0; 191 if (offset) 192 *offset = 0; 193 return; 194 } 195 196 static void createNullLocation(CXString *filename, unsigned *line, 197 unsigned *column, unsigned *offset = nullptr) { 198 if (filename) 199 *filename = cxstring::createEmpty(); 200 if (line) 201 *line = 0; 202 if (column) 203 *column = 0; 204 if (offset) 205 *offset = 0; 206 return; 207 } 208 209 extern "C" { 210 211 int clang_Location_isInSystemHeader(CXSourceLocation location) { 212 const SourceLocation Loc = 213 SourceLocation::getFromRawEncoding(location.int_data); 214 if (Loc.isInvalid()) 215 return 0; 216 217 const SourceManager &SM = 218 *static_cast<const SourceManager*>(location.ptr_data[0]); 219 return SM.isInSystemHeader(Loc); 220 } 221 222 int clang_Location_isFromMainFile(CXSourceLocation location) { 223 const SourceLocation Loc = 224 SourceLocation::getFromRawEncoding(location.int_data); 225 if (Loc.isInvalid()) 226 return 0; 227 228 const SourceManager &SM = 229 *static_cast<const SourceManager*>(location.ptr_data[0]); 230 return SM.isWrittenInMainFile(Loc); 231 } 232 233 void clang_getExpansionLocation(CXSourceLocation location, 234 CXFile *file, 235 unsigned *line, 236 unsigned *column, 237 unsigned *offset) { 238 239 if (!isASTUnitSourceLocation(location)) { 240 CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset); 241 return; 242 } 243 244 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); 245 246 if (!location.ptr_data[0] || Loc.isInvalid()) { 247 createNullLocation(file, line, column, offset); 248 return; 249 } 250 251 const SourceManager &SM = 252 *static_cast<const SourceManager*>(location.ptr_data[0]); 253 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc); 254 255 // Check that the FileID is invalid on the expansion location. 256 // This can manifest in invalid code. 257 FileID fileID = SM.getFileID(ExpansionLoc); 258 bool Invalid = false; 259 const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid); 260 if (Invalid || !sloc.isFile()) { 261 createNullLocation(file, line, column, offset); 262 return; 263 } 264 265 if (file) 266 *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc)); 267 if (line) 268 *line = SM.getExpansionLineNumber(ExpansionLoc); 269 if (column) 270 *column = SM.getExpansionColumnNumber(ExpansionLoc); 271 if (offset) 272 *offset = SM.getDecomposedLoc(ExpansionLoc).second; 273 } 274 275 void clang_getPresumedLocation(CXSourceLocation location, 276 CXString *filename, 277 unsigned *line, 278 unsigned *column) { 279 280 if (!isASTUnitSourceLocation(location)) { 281 // Other SourceLocation implementations do not support presumed locations 282 // at this time. 283 createNullLocation(filename, line, column); 284 return; 285 } 286 287 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); 288 289 if (!location.ptr_data[0] || Loc.isInvalid()) { 290 createNullLocation(filename, line, column); 291 return; 292 } 293 294 const SourceManager &SM = 295 *static_cast<const SourceManager *>(location.ptr_data[0]); 296 PresumedLoc PreLoc = SM.getPresumedLoc(Loc); 297 if (PreLoc.isInvalid()) { 298 createNullLocation(filename, line, column); 299 return; 300 } 301 302 if (filename) *filename = cxstring::createRef(PreLoc.getFilename()); 303 if (line) *line = PreLoc.getLine(); 304 if (column) *column = PreLoc.getColumn(); 305 } 306 307 void clang_getInstantiationLocation(CXSourceLocation location, 308 CXFile *file, 309 unsigned *line, 310 unsigned *column, 311 unsigned *offset) { 312 // Redirect to new API. 313 clang_getExpansionLocation(location, file, line, column, offset); 314 } 315 316 void clang_getSpellingLocation(CXSourceLocation location, 317 CXFile *file, 318 unsigned *line, 319 unsigned *column, 320 unsigned *offset) { 321 322 if (!isASTUnitSourceLocation(location)) { 323 CXLoadedDiagnostic::decodeLocation(location, file, line, 324 column, offset); 325 return; 326 } 327 328 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); 329 330 if (!location.ptr_data[0] || Loc.isInvalid()) 331 return createNullLocation(file, line, column, offset); 332 333 const SourceManager &SM = 334 *static_cast<const SourceManager*>(location.ptr_data[0]); 335 // FIXME: This should call SourceManager::getSpellingLoc(). 336 SourceLocation SpellLoc = SM.getFileLoc(Loc); 337 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc); 338 FileID FID = LocInfo.first; 339 unsigned FileOffset = LocInfo.second; 340 341 if (FID.isInvalid()) 342 return createNullLocation(file, line, column, offset); 343 344 if (file) 345 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID)); 346 if (line) 347 *line = SM.getLineNumber(FID, FileOffset); 348 if (column) 349 *column = SM.getColumnNumber(FID, FileOffset); 350 if (offset) 351 *offset = FileOffset; 352 } 353 354 void clang_getFileLocation(CXSourceLocation location, 355 CXFile *file, 356 unsigned *line, 357 unsigned *column, 358 unsigned *offset) { 359 360 if (!isASTUnitSourceLocation(location)) { 361 CXLoadedDiagnostic::decodeLocation(location, file, line, 362 column, offset); 363 return; 364 } 365 366 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); 367 368 if (!location.ptr_data[0] || Loc.isInvalid()) 369 return createNullLocation(file, line, column, offset); 370 371 const SourceManager &SM = 372 *static_cast<const SourceManager*>(location.ptr_data[0]); 373 SourceLocation FileLoc = SM.getFileLoc(Loc); 374 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc); 375 FileID FID = LocInfo.first; 376 unsigned FileOffset = LocInfo.second; 377 378 if (FID.isInvalid()) 379 return createNullLocation(file, line, column, offset); 380 381 if (file) 382 *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID)); 383 if (line) 384 *line = SM.getLineNumber(FID, FileOffset); 385 if (column) 386 *column = SM.getColumnNumber(FID, FileOffset); 387 if (offset) 388 *offset = FileOffset; 389 } 390 391 } // end extern "C" 392