xref: /netbsd-src/external/apache2/llvm/dist/clang/tools/libclang/CXSourceLocation.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
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