CXSourceLocation.cpp 12 KB

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