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 
     16 #include "CIndexer.h"
     17 #include "CXString.h"
     18 #include "CXSourceLocation.h"
     19 #include "CXTranslationUnit.h"
     20 #include "CXLoadedDiagnostic.h"
     21 
     22 using namespace clang;
     23 using namespace clang::cxstring;
     24 
     25 //===----------------------------------------------------------------------===//
     26 // Internal predicates on CXSourceLocations.
     27 //===----------------------------------------------------------------------===//
     28 
     29 static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
     30   // If the lowest bit is clear then the first ptr_data entry is a SourceManager
     31   // pointer, or the CXSourceLocation is a null location.
     32   return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
     33 }
     34 
     35 //===----------------------------------------------------------------------===//
     36 // Basic construction and comparison of CXSourceLocations and CXSourceRanges.
     37 //===----------------------------------------------------------------------===//
     38 
     39 extern "C" {
     40 
     41 CXSourceLocation clang_getNullLocation() {
     42   CXSourceLocation Result = { { 0, 0 }, 0 };
     43   return Result;
     44 }
     45 
     46 unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
     47   return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
     48           loc1.ptr_data[1] == loc2.ptr_data[1] &&
     49           loc1.int_data == loc2.int_data);
     50 }
     51 
     52 CXSourceRange clang_getNullRange() {
     53   CXSourceRange Result = { { 0, 0 }, 0, 0 };
     54   return Result;
     55 }
     56 
     57 CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
     58   if (!isASTUnitSourceLocation(begin)) {
     59     if (isASTUnitSourceLocation(end))
     60       return clang_getNullRange();
     61     CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
     62     return Result;
     63   }
     64 
     65   if (begin.ptr_data[0] != end.ptr_data[0] ||
     66       begin.ptr_data[1] != end.ptr_data[1])
     67     return clang_getNullRange();
     68 
     69   CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
     70                            begin.int_data, end.int_data };
     71 
     72   return Result;
     73 }
     74 
     75 unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
     76   return range1.ptr_data[0] == range2.ptr_data[0]
     77     && range1.ptr_data[1] == range2.ptr_data[1]
     78     && range1.begin_int_data == range2.begin_int_data
     79     && range1.end_int_data == range2.end_int_data;
     80 }
     81 
     82 int clang_Range_isNull(CXSourceRange range) {
     83   return clang_equalRanges(range, clang_getNullRange());
     84 }
     85 
     86 
     87 CXSourceLocation clang_getRangeStart(CXSourceRange range) {
     88   // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
     89   if ((uintptr_t)range.ptr_data[0] & 0x1) {
     90     CXSourceLocation Result = { { range.ptr_data[0], 0 }, 0 };
     91     return Result;
     92   }
     93 
     94   CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
     95     range.begin_int_data };
     96   return Result;
     97 }
     98 
     99 CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
    100   // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
    101   if ((uintptr_t)range.ptr_data[0] & 0x1) {
    102     CXSourceLocation Result = { { range.ptr_data[1], 0 }, 0 };
    103     return Result;
    104   }
    105 
    106   CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
    107     range.end_int_data };
    108   return Result;
    109 }
    110 
    111 } // end extern "C"
    112 
    113 //===----------------------------------------------------------------------===//
    114 //  Getting CXSourceLocations and CXSourceRanges from a translation unit.
    115 //===----------------------------------------------------------------------===//
    116 
    117 extern "C" {
    118 
    119 CXSourceLocation clang_getLocation(CXTranslationUnit tu,
    120                                    CXFile file,
    121                                    unsigned line,
    122                                    unsigned column) {
    123   if (!tu || !file)
    124     return clang_getNullLocation();
    125 
    126   bool Logging = ::getenv("LIBCLANG_LOGGING");
    127   ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
    128   ASTUnit::ConcurrencyCheck Check(*CXXUnit);
    129   const FileEntry *File = static_cast<const FileEntry *>(file);
    130   SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
    131   if (SLoc.isInvalid()) {
    132     if (Logging)
    133       llvm::errs() << "clang_getLocation(\"" << File->getName()
    134       << "\", " << line << ", " << column << ") = invalid\n";
    135     return clang_getNullLocation();
    136   }
    137 
    138   if (Logging)
    139     llvm::errs() << "clang_getLocation(\"" << File->getName()
    140     << "\", " << line << ", " << column << ") = "
    141     << SLoc.getRawEncoding() << "\n";
    142 
    143   return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
    144 }
    145 
    146 CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
    147                                             CXFile file,
    148                                             unsigned offset) {
    149   if (!tu || !file)
    150     return clang_getNullLocation();
    151 
    152   ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
    153 
    154   SourceLocation SLoc
    155     = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
    156 
    157   if (SLoc.isInvalid())
    158     return clang_getNullLocation();
    159 
    160   return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
    161 }
    162 
    163 } // end extern "C"
    164 
    165 //===----------------------------------------------------------------------===//
    166 // Routines for expanding and manipulating CXSourceLocations, regardless
    167 // of their origin.
    168 //===----------------------------------------------------------------------===//
    169 
    170 static void createNullLocation(CXFile *file, unsigned *line,
    171                                unsigned *column, unsigned *offset) {
    172   if (file)
    173     *file = 0;
    174   if (line)
    175     *line = 0;
    176   if (column)
    177     *column = 0;
    178   if (offset)
    179     *offset = 0;
    180   return;
    181 }
    182 
    183 static void createNullLocation(CXString *filename, unsigned *line,
    184                                unsigned *column, unsigned *offset = 0) {
    185   if (filename)
    186     *filename = createCXString("");
    187   if (line)
    188     *line = 0;
    189   if (column)
    190     *column = 0;
    191   if (offset)
    192     *offset = 0;
    193   return;
    194 }
    195 
    196 extern "C" {
    197 
    198 void clang_getExpansionLocation(CXSourceLocation location,
    199                                 CXFile *file,
    200                                 unsigned *line,
    201                                 unsigned *column,
    202                                 unsigned *offset) {
    203 
    204   if (!isASTUnitSourceLocation(location)) {
    205     CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
    206     return;
    207   }
    208 
    209   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
    210 
    211   if (!location.ptr_data[0] || Loc.isInvalid()) {
    212     createNullLocation(file, line, column, offset);
    213     return;
    214   }
    215 
    216   const SourceManager &SM =
    217   *static_cast<const SourceManager*>(location.ptr_data[0]);
    218   SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
    219 
    220   // Check that the FileID is invalid on the expansion location.
    221   // This can manifest in invalid code.
    222   FileID fileID = SM.getFileID(ExpansionLoc);
    223   bool Invalid = false;
    224   const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
    225   if (Invalid || !sloc.isFile()) {
    226     createNullLocation(file, line, column, offset);
    227     return;
    228   }
    229 
    230   if (file)
    231     *file = (void *)SM.getFileEntryForSLocEntry(sloc);
    232   if (line)
    233     *line = SM.getExpansionLineNumber(ExpansionLoc);
    234   if (column)
    235     *column = SM.getExpansionColumnNumber(ExpansionLoc);
    236   if (offset)
    237     *offset = SM.getDecomposedLoc(ExpansionLoc).second;
    238 }
    239 
    240 void clang_getPresumedLocation(CXSourceLocation location,
    241                                CXString *filename,
    242                                unsigned *line,
    243                                unsigned *column) {
    244 
    245   if (!isASTUnitSourceLocation(location)) {
    246     // Other SourceLocation implementations do not support presumed locations
    247     // at this time.
    248     createNullLocation(filename, line, column);
    249     return;
    250   }
    251 
    252   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
    253 
    254   if (!location.ptr_data[0] || Loc.isInvalid())
    255     createNullLocation(filename, line, column);
    256   else {
    257     const SourceManager &SM =
    258     *static_cast<const SourceManager*>(location.ptr_data[0]);
    259     PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
    260 
    261     if (filename)
    262       *filename = createCXString(PreLoc.getFilename());
    263     if (line)
    264       *line = PreLoc.getLine();
    265     if (column)
    266       *column = PreLoc.getColumn();
    267   }
    268 }
    269 
    270 void clang_getInstantiationLocation(CXSourceLocation location,
    271                                     CXFile *file,
    272                                     unsigned *line,
    273                                     unsigned *column,
    274                                     unsigned *offset) {
    275   // Redirect to new API.
    276   clang_getExpansionLocation(location, file, line, column, offset);
    277 }
    278 
    279 void clang_getSpellingLocation(CXSourceLocation location,
    280                                CXFile *file,
    281                                unsigned *line,
    282                                unsigned *column,
    283                                unsigned *offset) {
    284 
    285   if (!isASTUnitSourceLocation(location)) {
    286     CXLoadedDiagnostic::decodeLocation(location, file, line,
    287                                            column, offset);
    288     return;
    289   }
    290 
    291   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
    292 
    293   if (!location.ptr_data[0] || Loc.isInvalid())
    294     return createNullLocation(file, line, column, offset);
    295 
    296   const SourceManager &SM =
    297   *static_cast<const SourceManager*>(location.ptr_data[0]);
    298   SourceLocation SpellLoc = Loc;
    299   if (SpellLoc.isMacroID()) {
    300     SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc);
    301     if (SimpleSpellingLoc.isFileID() &&
    302         SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first))
    303       SpellLoc = SimpleSpellingLoc;
    304     else
    305       SpellLoc = SM.getExpansionLoc(SpellLoc);
    306   }
    307 
    308   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
    309   FileID FID = LocInfo.first;
    310   unsigned FileOffset = LocInfo.second;
    311 
    312   if (FID.isInvalid())
    313     return createNullLocation(file, line, column, offset);
    314 
    315   if (file)
    316     *file = (void *)SM.getFileEntryForID(FID);
    317   if (line)
    318     *line = SM.getLineNumber(FID, FileOffset);
    319   if (column)
    320     *column = SM.getColumnNumber(FID, FileOffset);
    321   if (offset)
    322     *offset = FileOffset;
    323 }
    324 
    325 } // end extern "C"
    326 
    327