327 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			327 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- CXSourceLocation.cpp - CXSourceLocations APIs ------------*- C++ -*-===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This file defines routines for manipulating CXSourceLocations.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "clang/Frontend/ASTUnit.h"
 | |
| 
 | |
| #include "CIndexer.h"
 | |
| #include "CXString.h"
 | |
| #include "CXSourceLocation.h"
 | |
| #include "CXTranslationUnit.h"
 | |
| #include "CXLoadedDiagnostic.h"
 | |
| 
 | |
| using namespace clang;
 | |
| using namespace clang::cxstring;
 | |
| 
 | |
| //===----------------------------------------------------------------------===//
 | |
| // Internal predicates on CXSourceLocations.
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
 | |
|   // If the lowest bit is clear then the first ptr_data entry is a SourceManager
 | |
|   // pointer, or the CXSourceLocation is a null location.
 | |
|   return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
 | |
| }
 | |
| 
 | |
| //===----------------------------------------------------------------------===//
 | |
| // Basic construction and comparison of CXSourceLocations and CXSourceRanges.
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| extern "C" {
 | |
|   
 | |
| CXSourceLocation clang_getNullLocation() {
 | |
|   CXSourceLocation Result = { { 0, 0 }, 0 };
 | |
|   return Result;
 | |
| }
 | |
| 
 | |
| unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
 | |
|   return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
 | |
|           loc1.ptr_data[1] == loc2.ptr_data[1] &&
 | |
|           loc1.int_data == loc2.int_data);
 | |
| }
 | |
| 
 | |
| CXSourceRange clang_getNullRange() {
 | |
|   CXSourceRange Result = { { 0, 0 }, 0, 0 };
 | |
|   return Result;
 | |
| }
 | |
| 
 | |
| CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
 | |
|   if (!isASTUnitSourceLocation(begin)) {
 | |
|     if (isASTUnitSourceLocation(end))
 | |
|       return clang_getNullRange();
 | |
|     CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
 | |
|     return Result;
 | |
|   }
 | |
|   
 | |
|   if (begin.ptr_data[0] != end.ptr_data[0] ||
 | |
|       begin.ptr_data[1] != end.ptr_data[1])
 | |
|     return clang_getNullRange();
 | |
|   
 | |
|   CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
 | |
|                            begin.int_data, end.int_data };
 | |
| 
 | |
|   return Result;
 | |
| }
 | |
| 
 | |
| unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
 | |
|   return range1.ptr_data[0] == range2.ptr_data[0]
 | |
|     && range1.ptr_data[1] == range2.ptr_data[1]
 | |
|     && range1.begin_int_data == range2.begin_int_data
 | |
|     && range1.end_int_data == range2.end_int_data;
 | |
| }
 | |
| 
 | |
| int clang_Range_isNull(CXSourceRange range) {
 | |
|   return clang_equalRanges(range, clang_getNullRange());
 | |
| }
 | |
|   
 | |
|   
 | |
| CXSourceLocation clang_getRangeStart(CXSourceRange range) {
 | |
|   // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
 | |
|   if ((uintptr_t)range.ptr_data[0] & 0x1) {
 | |
|     CXSourceLocation Result = { { range.ptr_data[0], 0 }, 0 };
 | |
|     return Result;    
 | |
|   }
 | |
|   
 | |
|   CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
 | |
|     range.begin_int_data };
 | |
|   return Result;
 | |
| }
 | |
| 
 | |
| CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
 | |
|   // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
 | |
|   if ((uintptr_t)range.ptr_data[0] & 0x1) {
 | |
|     CXSourceLocation Result = { { range.ptr_data[1], 0 }, 0 };
 | |
|     return Result;    
 | |
|   }
 | |
| 
 | |
|   CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
 | |
|     range.end_int_data };
 | |
|   return Result;
 | |
| }
 | |
| 
 | |
| } // end extern "C"
 | |
| 
 | |
| //===----------------------------------------------------------------------===//
 | |
| //  Getting CXSourceLocations and CXSourceRanges from a translation unit.
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| extern "C" {
 | |
|   
 | |
| CXSourceLocation clang_getLocation(CXTranslationUnit tu,
 | |
|                                    CXFile file,
 | |
|                                    unsigned line,
 | |
|                                    unsigned column) {
 | |
|   if (!tu || !file)
 | |
|     return clang_getNullLocation();
 | |
|   
 | |
|   bool Logging = ::getenv("LIBCLANG_LOGGING");
 | |
|   ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
 | |
|   ASTUnit::ConcurrencyCheck Check(*CXXUnit);
 | |
|   const FileEntry *File = static_cast<const FileEntry *>(file);
 | |
|   SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
 | |
|   if (SLoc.isInvalid()) {
 | |
|     if (Logging)
 | |
|       llvm::errs() << "clang_getLocation(\"" << File->getName() 
 | |
|       << "\", " << line << ", " << column << ") = invalid\n";
 | |
|     return clang_getNullLocation();
 | |
|   }
 | |
|   
 | |
|   if (Logging)
 | |
|     llvm::errs() << "clang_getLocation(\"" << File->getName() 
 | |
|     << "\", " << line << ", " << column << ") = " 
 | |
|     << SLoc.getRawEncoding() << "\n";
 | |
|   
 | |
|   return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
 | |
| }
 | |
|   
 | |
| CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
 | |
|                                             CXFile file,
 | |
|                                             unsigned offset) {
 | |
|   if (!tu || !file)
 | |
|     return clang_getNullLocation();
 | |
|   
 | |
|   ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
 | |
| 
 | |
|   SourceLocation SLoc 
 | |
|     = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
 | |
| 
 | |
|   if (SLoc.isInvalid())
 | |
|     return clang_getNullLocation();
 | |
|   
 | |
|   return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
 | |
| }
 | |
| 
 | |
| } // end extern "C"
 | |
| 
 | |
| //===----------------------------------------------------------------------===//
 | |
| // Routines for expanding and manipulating CXSourceLocations, regardless
 | |
| // of their origin.
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| static void createNullLocation(CXFile *file, unsigned *line,
 | |
|                                unsigned *column, unsigned *offset) {
 | |
|   if (file)
 | |
|     *file = 0;
 | |
|   if (line)
 | |
|     *line = 0;
 | |
|   if (column)
 | |
|     *column = 0;
 | |
|   if (offset)
 | |
|     *offset = 0;
 | |
|   return;
 | |
| }
 | |
| 
 | |
| static void createNullLocation(CXString *filename, unsigned *line,
 | |
|                                unsigned *column, unsigned *offset = 0) {
 | |
|   if (filename)
 | |
|     *filename = createCXString("");
 | |
|   if (line)
 | |
|     *line = 0;
 | |
|   if (column)
 | |
|     *column = 0;
 | |
|   if (offset)
 | |
|     *offset = 0;
 | |
|   return;
 | |
| }
 | |
| 
 | |
| extern "C" {
 | |
| 
 | |
| void clang_getExpansionLocation(CXSourceLocation location,
 | |
|                                 CXFile *file,
 | |
|                                 unsigned *line,
 | |
|                                 unsigned *column,
 | |
|                                 unsigned *offset) {
 | |
|   
 | |
|   if (!isASTUnitSourceLocation(location)) {
 | |
|     CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
 | |
| 
 | |
|   if (!location.ptr_data[0] || Loc.isInvalid()) {
 | |
|     createNullLocation(file, line, column, offset);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   const SourceManager &SM =
 | |
|   *static_cast<const SourceManager*>(location.ptr_data[0]);
 | |
|   SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
 | |
|   
 | |
|   // Check that the FileID is invalid on the expansion location.
 | |
|   // This can manifest in invalid code.
 | |
|   FileID fileID = SM.getFileID(ExpansionLoc);
 | |
|   bool Invalid = false;
 | |
|   const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
 | |
|   if (Invalid || !sloc.isFile()) {
 | |
|     createNullLocation(file, line, column, offset);
 | |
|     return;
 | |
|   }
 | |
|   
 | |
|   if (file)
 | |
|     *file = (void *)SM.getFileEntryForSLocEntry(sloc);
 | |
|   if (line)
 | |
|     *line = SM.getExpansionLineNumber(ExpansionLoc);
 | |
|   if (column)
 | |
|     *column = SM.getExpansionColumnNumber(ExpansionLoc);
 | |
|   if (offset)
 | |
|     *offset = SM.getDecomposedLoc(ExpansionLoc).second;
 | |
| }
 | |
| 
 | |
| void clang_getPresumedLocation(CXSourceLocation location,
 | |
|                                CXString *filename,
 | |
|                                unsigned *line,
 | |
|                                unsigned *column) {
 | |
|   
 | |
|   if (!isASTUnitSourceLocation(location)) {
 | |
|     // Other SourceLocation implementations do not support presumed locations
 | |
|     // at this time.
 | |
|     createNullLocation(filename, line, column);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
 | |
| 
 | |
|   if (!location.ptr_data[0] || Loc.isInvalid())
 | |
|     createNullLocation(filename, line, column);
 | |
|   else {
 | |
|     const SourceManager &SM =
 | |
|     *static_cast<const SourceManager*>(location.ptr_data[0]);
 | |
|     PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
 | |
|     
 | |
|     if (filename)
 | |
|       *filename = createCXString(PreLoc.getFilename());
 | |
|     if (line)
 | |
|       *line = PreLoc.getLine();
 | |
|     if (column)
 | |
|       *column = PreLoc.getColumn();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void clang_getInstantiationLocation(CXSourceLocation location,
 | |
|                                     CXFile *file,
 | |
|                                     unsigned *line,
 | |
|                                     unsigned *column,
 | |
|                                     unsigned *offset) {
 | |
|   // Redirect to new API.
 | |
|   clang_getExpansionLocation(location, file, line, column, offset);
 | |
| }
 | |
| 
 | |
| void clang_getSpellingLocation(CXSourceLocation location,
 | |
|                                CXFile *file,
 | |
|                                unsigned *line,
 | |
|                                unsigned *column,
 | |
|                                unsigned *offset) {
 | |
|   
 | |
|   if (!isASTUnitSourceLocation(location)) {
 | |
|     CXLoadedDiagnostic::decodeLocation(location, file, line,
 | |
|                                            column, offset);
 | |
|     return;
 | |
|   }
 | |
|   
 | |
|   SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
 | |
|   
 | |
|   if (!location.ptr_data[0] || Loc.isInvalid())
 | |
|     return createNullLocation(file, line, column, offset);
 | |
|   
 | |
|   const SourceManager &SM =
 | |
|   *static_cast<const SourceManager*>(location.ptr_data[0]);
 | |
|   SourceLocation SpellLoc = Loc;
 | |
|   if (SpellLoc.isMacroID()) {
 | |
|     SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc);
 | |
|     if (SimpleSpellingLoc.isFileID() &&
 | |
|         SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first))
 | |
|       SpellLoc = SimpleSpellingLoc;
 | |
|     else
 | |
|       SpellLoc = SM.getExpansionLoc(SpellLoc);
 | |
|   }
 | |
|   
 | |
|   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
 | |
|   FileID FID = LocInfo.first;
 | |
|   unsigned FileOffset = LocInfo.second;
 | |
|   
 | |
|   if (FID.isInvalid())
 | |
|     return createNullLocation(file, line, column, offset);
 | |
|   
 | |
|   if (file)
 | |
|     *file = (void *)SM.getFileEntryForID(FID);
 | |
|   if (line)
 | |
|     *line = SM.getLineNumber(FID, FileOffset);
 | |
|   if (column)
 | |
|     *column = SM.getColumnNumber(FID, FileOffset);
 | |
|   if (offset)
 | |
|     *offset = FileOffset;
 | |
| }
 | |
| 
 | |
| } // end extern "C"
 | |
| 
 |