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