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   return;
    194 }
    195 
    196 static void createNullLocation(CXString *filename, unsigned *line,
    197                                unsigned *column, unsigned *offset = nullptr) {
    198   if (filename)
    199     *filename = cxstring::createEmpty();
    200   if (line)
    201     *line = 0;
    202   if (column)
    203     *column = 0;
    204   if (offset)
    205     *offset = 0;
    206   return;
    207 }
    208 
    209 extern "C" {
    210 
    211 int clang_Location_isInSystemHeader(CXSourceLocation location) {
    212   const SourceLocation Loc =
    213     SourceLocation::getFromRawEncoding(location.int_data);
    214   if (Loc.isInvalid())
    215     return 0;
    216 
    217   const SourceManager &SM =
    218     *static_cast<const SourceManager*>(location.ptr_data[0]);
    219   return SM.isInSystemHeader(Loc);
    220 }
    221 
    222 int clang_Location_isFromMainFile(CXSourceLocation location) {
    223   const SourceLocation Loc =
    224     SourceLocation::getFromRawEncoding(location.int_data);
    225   if (Loc.isInvalid())
    226     return 0;
    227 
    228   const SourceManager &SM =
    229     *static_cast<const SourceManager*>(location.ptr_data[0]);
    230   return SM.isWrittenInMainFile(Loc);
    231 }
    232 
    233 void clang_getExpansionLocation(CXSourceLocation location,
    234                                 CXFile *file,
    235                                 unsigned *line,
    236                                 unsigned *column,
    237                                 unsigned *offset) {
    238 
    239   if (!isASTUnitSourceLocation(location)) {
    240     CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
    241     return;
    242   }
    243 
    244   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
    245 
    246   if (!location.ptr_data[0] || Loc.isInvalid()) {
    247     createNullLocation(file, line, column, offset);
    248     return;
    249   }
    250 
    251   const SourceManager &SM =
    252   *static_cast<const SourceManager*>(location.ptr_data[0]);
    253   SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
    254 
    255   // Check that the FileID is invalid on the expansion location.
    256   // This can manifest in invalid code.
    257   FileID fileID = SM.getFileID(ExpansionLoc);
    258   bool Invalid = false;
    259   const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
    260   if (Invalid || !sloc.isFile()) {
    261     createNullLocation(file, line, column, offset);
    262     return;
    263   }
    264 
    265   if (file)
    266     *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
    267   if (line)
    268     *line = SM.getExpansionLineNumber(ExpansionLoc);
    269   if (column)
    270     *column = SM.getExpansionColumnNumber(ExpansionLoc);
    271   if (offset)
    272     *offset = SM.getDecomposedLoc(ExpansionLoc).second;
    273 }
    274 
    275 void clang_getPresumedLocation(CXSourceLocation location,
    276                                CXString *filename,
    277                                unsigned *line,
    278                                unsigned *column) {
    279 
    280   if (!isASTUnitSourceLocation(location)) {
    281     // Other SourceLocation implementations do not support presumed locations
    282     // at this time.
    283     createNullLocation(filename, line, column);
    284     return;
    285   }
    286 
    287   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
    288 
    289   if (!location.ptr_data[0] || Loc.isInvalid()) {
    290     createNullLocation(filename, line, column);
    291     return;
    292   }
    293 
    294   const SourceManager &SM =
    295       *static_cast<const SourceManager *>(location.ptr_data[0]);
    296   PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
    297   if (PreLoc.isInvalid()) {
    298     createNullLocation(filename, line, column);
    299     return;
    300   }
    301 
    302   if (filename) *filename = cxstring::createRef(PreLoc.getFilename());
    303   if (line) *line = PreLoc.getLine();
    304   if (column) *column = PreLoc.getColumn();
    305 }
    306 
    307 void clang_getInstantiationLocation(CXSourceLocation location,
    308                                     CXFile *file,
    309                                     unsigned *line,
    310                                     unsigned *column,
    311                                     unsigned *offset) {
    312   // Redirect to new API.
    313   clang_getExpansionLocation(location, file, line, column, offset);
    314 }
    315 
    316 void clang_getSpellingLocation(CXSourceLocation location,
    317                                CXFile *file,
    318                                unsigned *line,
    319                                unsigned *column,
    320                                unsigned *offset) {
    321 
    322   if (!isASTUnitSourceLocation(location)) {
    323     CXLoadedDiagnostic::decodeLocation(location, file, line,
    324                                            column, offset);
    325     return;
    326   }
    327 
    328   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
    329 
    330   if (!location.ptr_data[0] || Loc.isInvalid())
    331     return createNullLocation(file, line, column, offset);
    332 
    333   const SourceManager &SM =
    334   *static_cast<const SourceManager*>(location.ptr_data[0]);
    335   // FIXME: This should call SourceManager::getSpellingLoc().
    336   SourceLocation SpellLoc = SM.getFileLoc(Loc);
    337   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
    338   FileID FID = LocInfo.first;
    339   unsigned FileOffset = LocInfo.second;
    340 
    341   if (FID.isInvalid())
    342     return createNullLocation(file, line, column, offset);
    343 
    344   if (file)
    345     *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
    346   if (line)
    347     *line = SM.getLineNumber(FID, FileOffset);
    348   if (column)
    349     *column = SM.getColumnNumber(FID, FileOffset);
    350   if (offset)
    351     *offset = FileOffset;
    352 }
    353 
    354 void clang_getFileLocation(CXSourceLocation location,
    355                            CXFile *file,
    356                            unsigned *line,
    357                            unsigned *column,
    358                            unsigned *offset) {
    359 
    360   if (!isASTUnitSourceLocation(location)) {
    361     CXLoadedDiagnostic::decodeLocation(location, file, line,
    362                                            column, offset);
    363     return;
    364   }
    365 
    366   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
    367 
    368   if (!location.ptr_data[0] || Loc.isInvalid())
    369     return createNullLocation(file, line, column, offset);
    370 
    371   const SourceManager &SM =
    372   *static_cast<const SourceManager*>(location.ptr_data[0]);
    373   SourceLocation FileLoc = SM.getFileLoc(Loc);
    374   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
    375   FileID FID = LocInfo.first;
    376   unsigned FileOffset = LocInfo.second;
    377 
    378   if (FID.isInvalid())
    379     return createNullLocation(file, line, column, offset);
    380 
    381   if (file)
    382     *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
    383   if (line)
    384     *line = SM.getLineNumber(FID, FileOffset);
    385   if (column)
    386     *column = SM.getColumnNumber(FID, FileOffset);
    387   if (offset)
    388     *offset = FileOffset;
    389 }
    390 
    391 } // end extern "C"
    392