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