106f32e7eSjoerg //===- CXSourceLocation.cpp - CXSourceLocations APIs ------------*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // This file defines routines for manipulating CXSourceLocations.
1006f32e7eSjoerg //
1106f32e7eSjoerg //===----------------------------------------------------------------------===//
1206f32e7eSjoerg
13*13fbcb42Sjoerg #include "CXSourceLocation.h"
1406f32e7eSjoerg #include "CIndexer.h"
1506f32e7eSjoerg #include "CLog.h"
1606f32e7eSjoerg #include "CXLoadedDiagnostic.h"
1706f32e7eSjoerg #include "CXString.h"
1806f32e7eSjoerg #include "CXTranslationUnit.h"
19*13fbcb42Sjoerg #include "clang/Basic/FileManager.h"
20*13fbcb42Sjoerg #include "clang/Frontend/ASTUnit.h"
2106f32e7eSjoerg #include "llvm/Support/Compiler.h"
2206f32e7eSjoerg #include "llvm/Support/Format.h"
2306f32e7eSjoerg
2406f32e7eSjoerg using namespace clang;
2506f32e7eSjoerg using namespace clang::cxindex;
2606f32e7eSjoerg
2706f32e7eSjoerg //===----------------------------------------------------------------------===//
2806f32e7eSjoerg // Internal predicates on CXSourceLocations.
2906f32e7eSjoerg //===----------------------------------------------------------------------===//
3006f32e7eSjoerg
isASTUnitSourceLocation(const CXSourceLocation & L)3106f32e7eSjoerg static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
3206f32e7eSjoerg // If the lowest bit is clear then the first ptr_data entry is a SourceManager
3306f32e7eSjoerg // pointer, or the CXSourceLocation is a null location.
3406f32e7eSjoerg return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
3506f32e7eSjoerg }
3606f32e7eSjoerg
3706f32e7eSjoerg //===----------------------------------------------------------------------===//
3806f32e7eSjoerg // Basic construction and comparison of CXSourceLocations and CXSourceRanges.
3906f32e7eSjoerg //===----------------------------------------------------------------------===//
4006f32e7eSjoerg
clang_getNullLocation()4106f32e7eSjoerg CXSourceLocation clang_getNullLocation() {
4206f32e7eSjoerg CXSourceLocation Result = { { nullptr, nullptr }, 0 };
4306f32e7eSjoerg return Result;
4406f32e7eSjoerg }
4506f32e7eSjoerg
clang_equalLocations(CXSourceLocation loc1,CXSourceLocation loc2)4606f32e7eSjoerg unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
4706f32e7eSjoerg return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
4806f32e7eSjoerg loc1.ptr_data[1] == loc2.ptr_data[1] &&
4906f32e7eSjoerg loc1.int_data == loc2.int_data);
5006f32e7eSjoerg }
5106f32e7eSjoerg
clang_getNullRange()5206f32e7eSjoerg CXSourceRange clang_getNullRange() {
5306f32e7eSjoerg CXSourceRange Result = { { nullptr, nullptr }, 0, 0 };
5406f32e7eSjoerg return Result;
5506f32e7eSjoerg }
5606f32e7eSjoerg
clang_getRange(CXSourceLocation begin,CXSourceLocation end)5706f32e7eSjoerg CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
5806f32e7eSjoerg if (!isASTUnitSourceLocation(begin)) {
5906f32e7eSjoerg if (isASTUnitSourceLocation(end))
6006f32e7eSjoerg return clang_getNullRange();
6106f32e7eSjoerg CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
6206f32e7eSjoerg return Result;
6306f32e7eSjoerg }
6406f32e7eSjoerg
6506f32e7eSjoerg if (begin.ptr_data[0] != end.ptr_data[0] ||
6606f32e7eSjoerg begin.ptr_data[1] != end.ptr_data[1])
6706f32e7eSjoerg return clang_getNullRange();
6806f32e7eSjoerg
6906f32e7eSjoerg CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
7006f32e7eSjoerg begin.int_data, end.int_data };
7106f32e7eSjoerg
7206f32e7eSjoerg return Result;
7306f32e7eSjoerg }
7406f32e7eSjoerg
clang_equalRanges(CXSourceRange range1,CXSourceRange range2)7506f32e7eSjoerg unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
7606f32e7eSjoerg return range1.ptr_data[0] == range2.ptr_data[0]
7706f32e7eSjoerg && range1.ptr_data[1] == range2.ptr_data[1]
7806f32e7eSjoerg && range1.begin_int_data == range2.begin_int_data
7906f32e7eSjoerg && range1.end_int_data == range2.end_int_data;
8006f32e7eSjoerg }
8106f32e7eSjoerg
clang_Range_isNull(CXSourceRange range)8206f32e7eSjoerg int clang_Range_isNull(CXSourceRange range) {
8306f32e7eSjoerg return clang_equalRanges(range, clang_getNullRange());
8406f32e7eSjoerg }
8506f32e7eSjoerg
8606f32e7eSjoerg
clang_getRangeStart(CXSourceRange range)8706f32e7eSjoerg CXSourceLocation clang_getRangeStart(CXSourceRange range) {
8806f32e7eSjoerg // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
8906f32e7eSjoerg if ((uintptr_t)range.ptr_data[0] & 0x1) {
9006f32e7eSjoerg CXSourceLocation Result = { { range.ptr_data[0], nullptr }, 0 };
9106f32e7eSjoerg return Result;
9206f32e7eSjoerg }
9306f32e7eSjoerg
9406f32e7eSjoerg CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
9506f32e7eSjoerg range.begin_int_data };
9606f32e7eSjoerg return Result;
9706f32e7eSjoerg }
9806f32e7eSjoerg
clang_getRangeEnd(CXSourceRange range)9906f32e7eSjoerg CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
10006f32e7eSjoerg // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
10106f32e7eSjoerg if ((uintptr_t)range.ptr_data[0] & 0x1) {
10206f32e7eSjoerg CXSourceLocation Result = { { range.ptr_data[1], nullptr }, 0 };
10306f32e7eSjoerg return Result;
10406f32e7eSjoerg }
10506f32e7eSjoerg
10606f32e7eSjoerg CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
10706f32e7eSjoerg range.end_int_data };
10806f32e7eSjoerg return Result;
10906f32e7eSjoerg }
11006f32e7eSjoerg
11106f32e7eSjoerg //===----------------------------------------------------------------------===//
11206f32e7eSjoerg // Getting CXSourceLocations and CXSourceRanges from a translation unit.
11306f32e7eSjoerg //===----------------------------------------------------------------------===//
11406f32e7eSjoerg
clang_getLocation(CXTranslationUnit TU,CXFile file,unsigned line,unsigned column)11506f32e7eSjoerg CXSourceLocation clang_getLocation(CXTranslationUnit TU,
11606f32e7eSjoerg CXFile file,
11706f32e7eSjoerg unsigned line,
11806f32e7eSjoerg unsigned column) {
11906f32e7eSjoerg if (cxtu::isNotUsableTU(TU)) {
12006f32e7eSjoerg LOG_BAD_TU(TU);
12106f32e7eSjoerg return clang_getNullLocation();
12206f32e7eSjoerg }
12306f32e7eSjoerg if (!file)
12406f32e7eSjoerg return clang_getNullLocation();
12506f32e7eSjoerg if (line == 0 || column == 0)
12606f32e7eSjoerg return clang_getNullLocation();
12706f32e7eSjoerg
12806f32e7eSjoerg LogRef Log = Logger::make(__func__);
12906f32e7eSjoerg ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
13006f32e7eSjoerg ASTUnit::ConcurrencyCheck Check(*CXXUnit);
13106f32e7eSjoerg const FileEntry *File = static_cast<const FileEntry *>(file);
13206f32e7eSjoerg SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
13306f32e7eSjoerg if (SLoc.isInvalid()) {
13406f32e7eSjoerg if (Log)
13506f32e7eSjoerg *Log << llvm::format("(\"%s\", %d, %d) = invalid",
13606f32e7eSjoerg File->getName().str().c_str(), line, column);
13706f32e7eSjoerg return clang_getNullLocation();
13806f32e7eSjoerg }
13906f32e7eSjoerg
14006f32e7eSjoerg CXSourceLocation CXLoc =
14106f32e7eSjoerg cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
14206f32e7eSjoerg if (Log)
14306f32e7eSjoerg *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName().str().c_str(),
14406f32e7eSjoerg line, column)
14506f32e7eSjoerg << CXLoc;
14606f32e7eSjoerg
14706f32e7eSjoerg return CXLoc;
14806f32e7eSjoerg }
14906f32e7eSjoerg
clang_getLocationForOffset(CXTranslationUnit TU,CXFile file,unsigned offset)15006f32e7eSjoerg CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
15106f32e7eSjoerg CXFile file,
15206f32e7eSjoerg unsigned offset) {
15306f32e7eSjoerg if (cxtu::isNotUsableTU(TU)) {
15406f32e7eSjoerg LOG_BAD_TU(TU);
15506f32e7eSjoerg return clang_getNullLocation();
15606f32e7eSjoerg }
15706f32e7eSjoerg if (!file)
15806f32e7eSjoerg return clang_getNullLocation();
15906f32e7eSjoerg
16006f32e7eSjoerg ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
16106f32e7eSjoerg
16206f32e7eSjoerg SourceLocation SLoc
16306f32e7eSjoerg = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
16406f32e7eSjoerg
16506f32e7eSjoerg if (SLoc.isInvalid())
16606f32e7eSjoerg return clang_getNullLocation();
16706f32e7eSjoerg
16806f32e7eSjoerg return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
16906f32e7eSjoerg }
17006f32e7eSjoerg
17106f32e7eSjoerg //===----------------------------------------------------------------------===//
17206f32e7eSjoerg // Routines for expanding and manipulating CXSourceLocations, regardless
17306f32e7eSjoerg // of their origin.
17406f32e7eSjoerg //===----------------------------------------------------------------------===//
17506f32e7eSjoerg
createNullLocation(CXFile * file,unsigned * line,unsigned * column,unsigned * offset)17606f32e7eSjoerg static void createNullLocation(CXFile *file, unsigned *line,
17706f32e7eSjoerg unsigned *column, unsigned *offset) {
17806f32e7eSjoerg if (file)
17906f32e7eSjoerg *file = nullptr;
18006f32e7eSjoerg if (line)
18106f32e7eSjoerg *line = 0;
18206f32e7eSjoerg if (column)
18306f32e7eSjoerg *column = 0;
18406f32e7eSjoerg if (offset)
18506f32e7eSjoerg *offset = 0;
18606f32e7eSjoerg }
18706f32e7eSjoerg
createNullLocation(CXString * filename,unsigned * line,unsigned * column,unsigned * offset=nullptr)18806f32e7eSjoerg static void createNullLocation(CXString *filename, unsigned *line,
18906f32e7eSjoerg unsigned *column, unsigned *offset = nullptr) {
19006f32e7eSjoerg if (filename)
19106f32e7eSjoerg *filename = cxstring::createEmpty();
19206f32e7eSjoerg if (line)
19306f32e7eSjoerg *line = 0;
19406f32e7eSjoerg if (column)
19506f32e7eSjoerg *column = 0;
19606f32e7eSjoerg if (offset)
19706f32e7eSjoerg *offset = 0;
19806f32e7eSjoerg }
19906f32e7eSjoerg
clang_Location_isInSystemHeader(CXSourceLocation location)20006f32e7eSjoerg int clang_Location_isInSystemHeader(CXSourceLocation location) {
20106f32e7eSjoerg const SourceLocation Loc =
20206f32e7eSjoerg SourceLocation::getFromRawEncoding(location.int_data);
20306f32e7eSjoerg if (Loc.isInvalid())
20406f32e7eSjoerg return 0;
20506f32e7eSjoerg
20606f32e7eSjoerg const SourceManager &SM =
20706f32e7eSjoerg *static_cast<const SourceManager*>(location.ptr_data[0]);
20806f32e7eSjoerg return SM.isInSystemHeader(Loc);
20906f32e7eSjoerg }
21006f32e7eSjoerg
clang_Location_isFromMainFile(CXSourceLocation location)21106f32e7eSjoerg int clang_Location_isFromMainFile(CXSourceLocation location) {
21206f32e7eSjoerg const SourceLocation Loc =
21306f32e7eSjoerg SourceLocation::getFromRawEncoding(location.int_data);
21406f32e7eSjoerg if (Loc.isInvalid())
21506f32e7eSjoerg return 0;
21606f32e7eSjoerg
21706f32e7eSjoerg const SourceManager &SM =
21806f32e7eSjoerg *static_cast<const SourceManager*>(location.ptr_data[0]);
21906f32e7eSjoerg return SM.isWrittenInMainFile(Loc);
22006f32e7eSjoerg }
22106f32e7eSjoerg
clang_getExpansionLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)22206f32e7eSjoerg void clang_getExpansionLocation(CXSourceLocation location,
22306f32e7eSjoerg CXFile *file,
22406f32e7eSjoerg unsigned *line,
22506f32e7eSjoerg unsigned *column,
22606f32e7eSjoerg unsigned *offset) {
22706f32e7eSjoerg if (!isASTUnitSourceLocation(location)) {
22806f32e7eSjoerg CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
22906f32e7eSjoerg return;
23006f32e7eSjoerg }
23106f32e7eSjoerg
23206f32e7eSjoerg SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
23306f32e7eSjoerg
23406f32e7eSjoerg if (!location.ptr_data[0] || Loc.isInvalid()) {
23506f32e7eSjoerg createNullLocation(file, line, column, offset);
23606f32e7eSjoerg return;
23706f32e7eSjoerg }
23806f32e7eSjoerg
23906f32e7eSjoerg const SourceManager &SM =
24006f32e7eSjoerg *static_cast<const SourceManager*>(location.ptr_data[0]);
24106f32e7eSjoerg SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
24206f32e7eSjoerg
24306f32e7eSjoerg // Check that the FileID is invalid on the expansion location.
24406f32e7eSjoerg // This can manifest in invalid code.
24506f32e7eSjoerg FileID fileID = SM.getFileID(ExpansionLoc);
24606f32e7eSjoerg bool Invalid = false;
24706f32e7eSjoerg const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
24806f32e7eSjoerg if (Invalid || !sloc.isFile()) {
24906f32e7eSjoerg createNullLocation(file, line, column, offset);
25006f32e7eSjoerg return;
25106f32e7eSjoerg }
25206f32e7eSjoerg
25306f32e7eSjoerg if (file)
25406f32e7eSjoerg *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
25506f32e7eSjoerg if (line)
25606f32e7eSjoerg *line = SM.getExpansionLineNumber(ExpansionLoc);
25706f32e7eSjoerg if (column)
25806f32e7eSjoerg *column = SM.getExpansionColumnNumber(ExpansionLoc);
25906f32e7eSjoerg if (offset)
26006f32e7eSjoerg *offset = SM.getDecomposedLoc(ExpansionLoc).second;
26106f32e7eSjoerg }
26206f32e7eSjoerg
clang_getPresumedLocation(CXSourceLocation location,CXString * filename,unsigned * line,unsigned * column)26306f32e7eSjoerg void clang_getPresumedLocation(CXSourceLocation location,
26406f32e7eSjoerg CXString *filename,
26506f32e7eSjoerg unsigned *line,
26606f32e7eSjoerg unsigned *column) {
26706f32e7eSjoerg if (!isASTUnitSourceLocation(location)) {
26806f32e7eSjoerg // Other SourceLocation implementations do not support presumed locations
26906f32e7eSjoerg // at this time.
27006f32e7eSjoerg createNullLocation(filename, line, column);
27106f32e7eSjoerg return;
27206f32e7eSjoerg }
27306f32e7eSjoerg
27406f32e7eSjoerg SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
27506f32e7eSjoerg
27606f32e7eSjoerg if (!location.ptr_data[0] || Loc.isInvalid()) {
27706f32e7eSjoerg createNullLocation(filename, line, column);
27806f32e7eSjoerg return;
27906f32e7eSjoerg }
28006f32e7eSjoerg
28106f32e7eSjoerg const SourceManager &SM =
28206f32e7eSjoerg *static_cast<const SourceManager *>(location.ptr_data[0]);
28306f32e7eSjoerg PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
28406f32e7eSjoerg if (PreLoc.isInvalid()) {
28506f32e7eSjoerg createNullLocation(filename, line, column);
28606f32e7eSjoerg return;
28706f32e7eSjoerg }
28806f32e7eSjoerg
28906f32e7eSjoerg if (filename) *filename = cxstring::createRef(PreLoc.getFilename());
29006f32e7eSjoerg if (line) *line = PreLoc.getLine();
29106f32e7eSjoerg if (column) *column = PreLoc.getColumn();
29206f32e7eSjoerg }
29306f32e7eSjoerg
clang_getInstantiationLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)29406f32e7eSjoerg void clang_getInstantiationLocation(CXSourceLocation location,
29506f32e7eSjoerg CXFile *file,
29606f32e7eSjoerg unsigned *line,
29706f32e7eSjoerg unsigned *column,
29806f32e7eSjoerg unsigned *offset) {
29906f32e7eSjoerg // Redirect to new API.
30006f32e7eSjoerg clang_getExpansionLocation(location, file, line, column, offset);
30106f32e7eSjoerg }
30206f32e7eSjoerg
clang_getSpellingLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)30306f32e7eSjoerg void clang_getSpellingLocation(CXSourceLocation location,
30406f32e7eSjoerg CXFile *file,
30506f32e7eSjoerg unsigned *line,
30606f32e7eSjoerg unsigned *column,
30706f32e7eSjoerg unsigned *offset) {
30806f32e7eSjoerg if (!isASTUnitSourceLocation(location)) {
30906f32e7eSjoerg CXLoadedDiagnostic::decodeLocation(location, file, line,
31006f32e7eSjoerg column, offset);
31106f32e7eSjoerg return;
31206f32e7eSjoerg }
31306f32e7eSjoerg
31406f32e7eSjoerg SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
31506f32e7eSjoerg
31606f32e7eSjoerg if (!location.ptr_data[0] || Loc.isInvalid())
31706f32e7eSjoerg return createNullLocation(file, line, column, offset);
31806f32e7eSjoerg
31906f32e7eSjoerg const SourceManager &SM =
32006f32e7eSjoerg *static_cast<const SourceManager*>(location.ptr_data[0]);
32106f32e7eSjoerg // FIXME: This should call SourceManager::getSpellingLoc().
32206f32e7eSjoerg SourceLocation SpellLoc = SM.getFileLoc(Loc);
32306f32e7eSjoerg std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
32406f32e7eSjoerg FileID FID = LocInfo.first;
32506f32e7eSjoerg unsigned FileOffset = LocInfo.second;
32606f32e7eSjoerg
32706f32e7eSjoerg if (FID.isInvalid())
32806f32e7eSjoerg return createNullLocation(file, line, column, offset);
32906f32e7eSjoerg
33006f32e7eSjoerg if (file)
33106f32e7eSjoerg *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
33206f32e7eSjoerg if (line)
33306f32e7eSjoerg *line = SM.getLineNumber(FID, FileOffset);
33406f32e7eSjoerg if (column)
33506f32e7eSjoerg *column = SM.getColumnNumber(FID, FileOffset);
33606f32e7eSjoerg if (offset)
33706f32e7eSjoerg *offset = FileOffset;
33806f32e7eSjoerg }
33906f32e7eSjoerg
clang_getFileLocation(CXSourceLocation location,CXFile * file,unsigned * line,unsigned * column,unsigned * offset)34006f32e7eSjoerg void clang_getFileLocation(CXSourceLocation location,
34106f32e7eSjoerg CXFile *file,
34206f32e7eSjoerg unsigned *line,
34306f32e7eSjoerg unsigned *column,
34406f32e7eSjoerg unsigned *offset) {
34506f32e7eSjoerg if (!isASTUnitSourceLocation(location)) {
34606f32e7eSjoerg CXLoadedDiagnostic::decodeLocation(location, file, line,
34706f32e7eSjoerg column, offset);
34806f32e7eSjoerg return;
34906f32e7eSjoerg }
35006f32e7eSjoerg
35106f32e7eSjoerg SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
35206f32e7eSjoerg
35306f32e7eSjoerg if (!location.ptr_data[0] || Loc.isInvalid())
35406f32e7eSjoerg return createNullLocation(file, line, column, offset);
35506f32e7eSjoerg
35606f32e7eSjoerg const SourceManager &SM =
35706f32e7eSjoerg *static_cast<const SourceManager*>(location.ptr_data[0]);
35806f32e7eSjoerg SourceLocation FileLoc = SM.getFileLoc(Loc);
35906f32e7eSjoerg std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
36006f32e7eSjoerg FileID FID = LocInfo.first;
36106f32e7eSjoerg unsigned FileOffset = LocInfo.second;
36206f32e7eSjoerg
36306f32e7eSjoerg if (FID.isInvalid())
36406f32e7eSjoerg return createNullLocation(file, line, column, offset);
36506f32e7eSjoerg
36606f32e7eSjoerg if (file)
36706f32e7eSjoerg *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
36806f32e7eSjoerg if (line)
36906f32e7eSjoerg *line = SM.getLineNumber(FID, FileOffset);
37006f32e7eSjoerg if (column)
37106f32e7eSjoerg *column = SM.getColumnNumber(FID, FileOffset);
37206f32e7eSjoerg if (offset)
37306f32e7eSjoerg *offset = FileOffset;
37406f32e7eSjoerg }
375