17330f729Sjoerg //===- CXSourceLocation.cpp - CXSourceLocations APIs ------------*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file defines routines for manipulating CXSourceLocations.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg
13*e038c9c4Sjoerg #include "CXSourceLocation.h"
147330f729Sjoerg #include "CIndexer.h"
157330f729Sjoerg #include "CLog.h"
167330f729Sjoerg #include "CXLoadedDiagnostic.h"
177330f729Sjoerg #include "CXString.h"
187330f729Sjoerg #include "CXTranslationUnit.h"
19*e038c9c4Sjoerg #include "clang/Basic/FileManager.h"
20*e038c9c4Sjoerg #include "clang/Frontend/ASTUnit.h"
217330f729Sjoerg #include "llvm/Support/Compiler.h"
227330f729Sjoerg #include "llvm/Support/Format.h"
237330f729Sjoerg
247330f729Sjoerg using namespace clang;
257330f729Sjoerg using namespace clang::cxindex;
267330f729Sjoerg
277330f729Sjoerg //===----------------------------------------------------------------------===//
287330f729Sjoerg // Internal predicates on CXSourceLocations.
297330f729Sjoerg //===----------------------------------------------------------------------===//
307330f729Sjoerg
isASTUnitSourceLocation(const CXSourceLocation & L)317330f729Sjoerg static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
327330f729Sjoerg // If the lowest bit is clear then the first ptr_data entry is a SourceManager
337330f729Sjoerg // pointer, or the CXSourceLocation is a null location.
347330f729Sjoerg return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
357330f729Sjoerg }
367330f729Sjoerg
377330f729Sjoerg //===----------------------------------------------------------------------===//
387330f729Sjoerg // Basic construction and comparison of CXSourceLocations and CXSourceRanges.
397330f729Sjoerg //===----------------------------------------------------------------------===//
407330f729Sjoerg
clang_getNullLocation()417330f729Sjoerg CXSourceLocation clang_getNullLocation() {
427330f729Sjoerg CXSourceLocation Result = { { nullptr, nullptr }, 0 };
437330f729Sjoerg return Result;
447330f729Sjoerg }
457330f729Sjoerg
clang_equalLocations(CXSourceLocation loc1,CXSourceLocation loc2)467330f729Sjoerg unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
477330f729Sjoerg return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
487330f729Sjoerg loc1.ptr_data[1] == loc2.ptr_data[1] &&
497330f729Sjoerg loc1.int_data == loc2.int_data);
507330f729Sjoerg }
517330f729Sjoerg
clang_getNullRange()527330f729Sjoerg CXSourceRange clang_getNullRange() {
537330f729Sjoerg CXSourceRange Result = { { nullptr, nullptr }, 0, 0 };
547330f729Sjoerg return Result;
557330f729Sjoerg }
567330f729Sjoerg
clang_getRange(CXSourceLocation begin,CXSourceLocation end)577330f729Sjoerg CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
587330f729Sjoerg if (!isASTUnitSourceLocation(begin)) {
597330f729Sjoerg if (isASTUnitSourceLocation(end))
607330f729Sjoerg return clang_getNullRange();
617330f729Sjoerg CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
627330f729Sjoerg return Result;
637330f729Sjoerg }
647330f729Sjoerg
657330f729Sjoerg if (begin.ptr_data[0] != end.ptr_data[0] ||
667330f729Sjoerg begin.ptr_data[1] != end.ptr_data[1])
677330f729Sjoerg return clang_getNullRange();
687330f729Sjoerg
697330f729Sjoerg CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
707330f729Sjoerg begin.int_data, end.int_data };
717330f729Sjoerg
727330f729Sjoerg return Result;
737330f729Sjoerg }
747330f729Sjoerg
clang_equalRanges(CXSourceRange range1,CXSourceRange range2)757330f729Sjoerg unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
767330f729Sjoerg return range1.ptr_data[0] == range2.ptr_data[0]
777330f729Sjoerg && range1.ptr_data[1] == range2.ptr_data[1]
787330f729Sjoerg && range1.begin_int_data == range2.begin_int_data
797330f729Sjoerg && range1.end_int_data == range2.end_int_data;
807330f729Sjoerg }
817330f729Sjoerg
clang_Range_isNull(CXSourceRange range)827330f729Sjoerg int clang_Range_isNull(CXSourceRange range) {
837330f729Sjoerg return clang_equalRanges(range, clang_getNullRange());
847330f729Sjoerg }
857330f729Sjoerg
867330f729Sjoerg
clang_getRangeStart(CXSourceRange range)877330f729Sjoerg CXSourceLocation clang_getRangeStart(CXSourceRange range) {
887330f729Sjoerg // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
897330f729Sjoerg if ((uintptr_t)range.ptr_data[0] & 0x1) {
907330f729Sjoerg CXSourceLocation Result = { { range.ptr_data[0], nullptr }, 0 };
917330f729Sjoerg return Result;
927330f729Sjoerg }
937330f729Sjoerg
947330f729Sjoerg CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
957330f729Sjoerg range.begin_int_data };
967330f729Sjoerg return Result;
977330f729Sjoerg }
987330f729Sjoerg
clang_getRangeEnd(CXSourceRange range)997330f729Sjoerg CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
1007330f729Sjoerg // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
1017330f729Sjoerg if ((uintptr_t)range.ptr_data[0] & 0x1) {
1027330f729Sjoerg CXSourceLocation Result = { { range.ptr_data[1], nullptr }, 0 };
1037330f729Sjoerg return Result;
1047330f729Sjoerg }
1057330f729Sjoerg
1067330f729Sjoerg CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
1077330f729Sjoerg range.end_int_data };
1087330f729Sjoerg return Result;
1097330f729Sjoerg }
1107330f729Sjoerg
1117330f729Sjoerg //===----------------------------------------------------------------------===//
1127330f729Sjoerg // Getting CXSourceLocations and CXSourceRanges from a translation unit.
1137330f729Sjoerg //===----------------------------------------------------------------------===//
1147330f729Sjoerg
clang_getLocation(CXTranslationUnit TU,CXFile file,unsigned line,unsigned column)1157330f729Sjoerg CXSourceLocation clang_getLocation(CXTranslationUnit TU,
1167330f729Sjoerg CXFile file,
1177330f729Sjoerg unsigned line,
1187330f729Sjoerg unsigned column) {
1197330f729Sjoerg if (cxtu::isNotUsableTU(TU)) {
1207330f729Sjoerg LOG_BAD_TU(TU);
1217330f729Sjoerg return clang_getNullLocation();
1227330f729Sjoerg }
1237330f729Sjoerg if (!file)
1247330f729Sjoerg return clang_getNullLocation();
1257330f729Sjoerg if (line == 0 || column == 0)
1267330f729Sjoerg return clang_getNullLocation();
1277330f729Sjoerg
1287330f729Sjoerg LogRef Log = Logger::make(__func__);
1297330f729Sjoerg ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
1307330f729Sjoerg ASTUnit::ConcurrencyCheck Check(*CXXUnit);
1317330f729Sjoerg const FileEntry *File = static_cast<const FileEntry *>(file);
1327330f729Sjoerg SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
1337330f729Sjoerg if (SLoc.isInvalid()) {
1347330f729Sjoerg if (Log)
1357330f729Sjoerg *Log << llvm::format("(\"%s\", %d, %d) = invalid",
1367330f729Sjoerg File->getName().str().c_str(), line, column);
1377330f729Sjoerg return clang_getNullLocation();
1387330f729Sjoerg }
1397330f729Sjoerg
1407330f729Sjoerg CXSourceLocation CXLoc =
1417330f729Sjoerg cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
1427330f729Sjoerg if (Log)
1437330f729Sjoerg *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName().str().c_str(),
1447330f729Sjoerg line, column)
1457330f729Sjoerg << CXLoc;
1467330f729Sjoerg
1477330f729Sjoerg return CXLoc;
1487330f729Sjoerg }
1497330f729Sjoerg
clang_getLocationForOffset(CXTranslationUnit TU,CXFile file,unsigned offset)1507330f729Sjoerg CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
1517330f729Sjoerg CXFile file,
1527330f729Sjoerg unsigned offset) {
1537330f729Sjoerg if (cxtu::isNotUsableTU(TU)) {
1547330f729Sjoerg LOG_BAD_TU(TU);
1557330f729Sjoerg return clang_getNullLocation();
1567330f729Sjoerg }
1577330f729Sjoerg if (!file)
1587330f729Sjoerg return clang_getNullLocation();
1597330f729Sjoerg
1607330f729Sjoerg ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
1617330f729Sjoerg
1627330f729Sjoerg SourceLocation SLoc
1637330f729Sjoerg = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
1647330f729Sjoerg
1657330f729Sjoerg if (SLoc.isInvalid())
1667330f729Sjoerg return clang_getNullLocation();
1677330f729Sjoerg
1687330f729Sjoerg return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
1697330f729Sjoerg }
1707330f729Sjoerg
1717330f729Sjoerg //===----------------------------------------------------------------------===//
1727330f729Sjoerg // Routines for expanding and manipulating CXSourceLocations, regardless
1737330f729Sjoerg // of their origin.
1747330f729Sjoerg //===----------------------------------------------------------------------===//
1757330f729Sjoerg
createNullLocation(CXFile * file,unsigned * line,unsigned * column,unsigned * offset)1767330f729Sjoerg static void createNullLocation(CXFile *file, unsigned *line,
1777330f729Sjoerg unsigned *column, unsigned *offset) {
1787330f729Sjoerg if (file)
1797330f729Sjoerg *file = nullptr;
1807330f729Sjoerg if (line)
1817330f729Sjoerg *line = 0;
1827330f729Sjoerg if (column)
1837330f729Sjoerg *column = 0;
1847330f729Sjoerg if (offset)
1857330f729Sjoerg *offset = 0;
1867330f729Sjoerg }
1877330f729Sjoerg
createNullLocation(CXString * filename,unsigned * line,unsigned * column,unsigned * offset=nullptr)1887330f729Sjoerg static void createNullLocation(CXString *filename, unsigned *line,
1897330f729Sjoerg unsigned *column, unsigned *offset = nullptr) {
1907330f729Sjoerg if (filename)
1917330f729Sjoerg *filename = cxstring::createEmpty();
1927330f729Sjoerg if (line)
1937330f729Sjoerg *line = 0;
1947330f729Sjoerg if (column)
1957330f729Sjoerg *column = 0;
1967330f729Sjoerg if (offset)
1977330f729Sjoerg *offset = 0;
1987330f729Sjoerg }
1997330f729Sjoerg
clang_Location_isInSystemHeader(CXSourceLocation location)2007330f729Sjoerg int clang_Location_isInSystemHeader(CXSourceLocation location) {
2017330f729Sjoerg const SourceLocation Loc =
2027330f729Sjoerg SourceLocation::getFromRawEncoding(location.int_data);
2037330f729Sjoerg if (Loc.isInvalid())
2047330f729Sjoerg return 0;
2057330f729Sjoerg
2067330f729Sjoerg const SourceManager &SM =
2077330f729Sjoerg *static_cast<const SourceManager*>(location.ptr_data[0]);
2087330f729Sjoerg return SM.isInSystemHeader(Loc);
2097330f729Sjoerg }
2107330f729Sjoerg
clang_Location_isFromMainFile(CXSourceLocation location)2117330f729Sjoerg int clang_Location_isFromMainFile(CXSourceLocation location) {
2127330f729Sjoerg const SourceLocation Loc =
2137330f729Sjoerg SourceLocation::getFromRawEncoding(location.int_data);
2147330f729Sjoerg if (Loc.isInvalid())
2157330f729Sjoerg return 0;
2167330f729Sjoerg
2177330f729Sjoerg const SourceManager &SM =
2187330f729Sjoerg *static_cast<const SourceManager*>(location.ptr_data[0]);
2197330f729Sjoerg return SM.isWrittenInMainFile(Loc);
2207330f729Sjoerg }
2217330f729Sjoerg
clang_getExpansionLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)2227330f729Sjoerg void clang_getExpansionLocation(CXSourceLocation location,
2237330f729Sjoerg CXFile *file,
2247330f729Sjoerg unsigned *line,
2257330f729Sjoerg unsigned *column,
2267330f729Sjoerg unsigned *offset) {
2277330f729Sjoerg if (!isASTUnitSourceLocation(location)) {
2287330f729Sjoerg CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
2297330f729Sjoerg return;
2307330f729Sjoerg }
2317330f729Sjoerg
2327330f729Sjoerg SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
2337330f729Sjoerg
2347330f729Sjoerg if (!location.ptr_data[0] || Loc.isInvalid()) {
2357330f729Sjoerg createNullLocation(file, line, column, offset);
2367330f729Sjoerg return;
2377330f729Sjoerg }
2387330f729Sjoerg
2397330f729Sjoerg const SourceManager &SM =
2407330f729Sjoerg *static_cast<const SourceManager*>(location.ptr_data[0]);
2417330f729Sjoerg SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
2427330f729Sjoerg
2437330f729Sjoerg // Check that the FileID is invalid on the expansion location.
2447330f729Sjoerg // This can manifest in invalid code.
2457330f729Sjoerg FileID fileID = SM.getFileID(ExpansionLoc);
2467330f729Sjoerg bool Invalid = false;
2477330f729Sjoerg const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
2487330f729Sjoerg if (Invalid || !sloc.isFile()) {
2497330f729Sjoerg createNullLocation(file, line, column, offset);
2507330f729Sjoerg return;
2517330f729Sjoerg }
2527330f729Sjoerg
2537330f729Sjoerg if (file)
2547330f729Sjoerg *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
2557330f729Sjoerg if (line)
2567330f729Sjoerg *line = SM.getExpansionLineNumber(ExpansionLoc);
2577330f729Sjoerg if (column)
2587330f729Sjoerg *column = SM.getExpansionColumnNumber(ExpansionLoc);
2597330f729Sjoerg if (offset)
2607330f729Sjoerg *offset = SM.getDecomposedLoc(ExpansionLoc).second;
2617330f729Sjoerg }
2627330f729Sjoerg
clang_getPresumedLocation(CXSourceLocation location,CXString * filename,unsigned * line,unsigned * column)2637330f729Sjoerg void clang_getPresumedLocation(CXSourceLocation location,
2647330f729Sjoerg CXString *filename,
2657330f729Sjoerg unsigned *line,
2667330f729Sjoerg unsigned *column) {
2677330f729Sjoerg if (!isASTUnitSourceLocation(location)) {
2687330f729Sjoerg // Other SourceLocation implementations do not support presumed locations
2697330f729Sjoerg // at this time.
2707330f729Sjoerg createNullLocation(filename, line, column);
2717330f729Sjoerg return;
2727330f729Sjoerg }
2737330f729Sjoerg
2747330f729Sjoerg SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
2757330f729Sjoerg
2767330f729Sjoerg if (!location.ptr_data[0] || Loc.isInvalid()) {
2777330f729Sjoerg createNullLocation(filename, line, column);
2787330f729Sjoerg return;
2797330f729Sjoerg }
2807330f729Sjoerg
2817330f729Sjoerg const SourceManager &SM =
2827330f729Sjoerg *static_cast<const SourceManager *>(location.ptr_data[0]);
2837330f729Sjoerg PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
2847330f729Sjoerg if (PreLoc.isInvalid()) {
2857330f729Sjoerg createNullLocation(filename, line, column);
2867330f729Sjoerg return;
2877330f729Sjoerg }
2887330f729Sjoerg
2897330f729Sjoerg if (filename) *filename = cxstring::createRef(PreLoc.getFilename());
2907330f729Sjoerg if (line) *line = PreLoc.getLine();
2917330f729Sjoerg if (column) *column = PreLoc.getColumn();
2927330f729Sjoerg }
2937330f729Sjoerg
clang_getInstantiationLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)2947330f729Sjoerg void clang_getInstantiationLocation(CXSourceLocation location,
2957330f729Sjoerg CXFile *file,
2967330f729Sjoerg unsigned *line,
2977330f729Sjoerg unsigned *column,
2987330f729Sjoerg unsigned *offset) {
2997330f729Sjoerg // Redirect to new API.
3007330f729Sjoerg clang_getExpansionLocation(location, file, line, column, offset);
3017330f729Sjoerg }
3027330f729Sjoerg
clang_getSpellingLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)3037330f729Sjoerg void clang_getSpellingLocation(CXSourceLocation location,
3047330f729Sjoerg CXFile *file,
3057330f729Sjoerg unsigned *line,
3067330f729Sjoerg unsigned *column,
3077330f729Sjoerg unsigned *offset) {
3087330f729Sjoerg if (!isASTUnitSourceLocation(location)) {
3097330f729Sjoerg CXLoadedDiagnostic::decodeLocation(location, file, line,
3107330f729Sjoerg column, offset);
3117330f729Sjoerg return;
3127330f729Sjoerg }
3137330f729Sjoerg
3147330f729Sjoerg SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
3157330f729Sjoerg
3167330f729Sjoerg if (!location.ptr_data[0] || Loc.isInvalid())
3177330f729Sjoerg return createNullLocation(file, line, column, offset);
3187330f729Sjoerg
3197330f729Sjoerg const SourceManager &SM =
3207330f729Sjoerg *static_cast<const SourceManager*>(location.ptr_data[0]);
3217330f729Sjoerg // FIXME: This should call SourceManager::getSpellingLoc().
3227330f729Sjoerg SourceLocation SpellLoc = SM.getFileLoc(Loc);
3237330f729Sjoerg std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
3247330f729Sjoerg FileID FID = LocInfo.first;
3257330f729Sjoerg unsigned FileOffset = LocInfo.second;
3267330f729Sjoerg
3277330f729Sjoerg if (FID.isInvalid())
3287330f729Sjoerg return createNullLocation(file, line, column, offset);
3297330f729Sjoerg
3307330f729Sjoerg if (file)
3317330f729Sjoerg *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
3327330f729Sjoerg if (line)
3337330f729Sjoerg *line = SM.getLineNumber(FID, FileOffset);
3347330f729Sjoerg if (column)
3357330f729Sjoerg *column = SM.getColumnNumber(FID, FileOffset);
3367330f729Sjoerg if (offset)
3377330f729Sjoerg *offset = FileOffset;
3387330f729Sjoerg }
3397330f729Sjoerg
clang_getFileLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)3407330f729Sjoerg void clang_getFileLocation(CXSourceLocation location,
3417330f729Sjoerg CXFile *file,
3427330f729Sjoerg unsigned *line,
3437330f729Sjoerg unsigned *column,
3447330f729Sjoerg unsigned *offset) {
3457330f729Sjoerg if (!isASTUnitSourceLocation(location)) {
3467330f729Sjoerg CXLoadedDiagnostic::decodeLocation(location, file, line,
3477330f729Sjoerg column, offset);
3487330f729Sjoerg return;
3497330f729Sjoerg }
3507330f729Sjoerg
3517330f729Sjoerg SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
3527330f729Sjoerg
3537330f729Sjoerg if (!location.ptr_data[0] || Loc.isInvalid())
3547330f729Sjoerg return createNullLocation(file, line, column, offset);
3557330f729Sjoerg
3567330f729Sjoerg const SourceManager &SM =
3577330f729Sjoerg *static_cast<const SourceManager*>(location.ptr_data[0]);
3587330f729Sjoerg SourceLocation FileLoc = SM.getFileLoc(Loc);
3597330f729Sjoerg std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
3607330f729Sjoerg FileID FID = LocInfo.first;
3617330f729Sjoerg unsigned FileOffset = LocInfo.second;
3627330f729Sjoerg
3637330f729Sjoerg if (FID.isInvalid())
3647330f729Sjoerg return createNullLocation(file, line, column, offset);
3657330f729Sjoerg
3667330f729Sjoerg if (file)
3677330f729Sjoerg *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
3687330f729Sjoerg if (line)
3697330f729Sjoerg *line = SM.getLineNumber(FID, FileOffset);
3707330f729Sjoerg if (column)
3717330f729Sjoerg *column = SM.getColumnNumber(FID, FileOffset);
3727330f729Sjoerg if (offset)
3737330f729Sjoerg *offset = FileOffset;
3747330f729Sjoerg }
375