From 1db19dea8d221f27be46332d668d1e2decb7f1ab Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 19 Jan 2010 21:36:55 +0000 Subject: [PATCH] Rework the CXSourceLocation and CXSourceRange APIs. They are now opaque data structures accessed through the new functions clang_getInstantiationLocation(), clang_getRangeStart(), and clang_getRangeEnd(). The new API permits later extensions to introduce new functions to allow CIndex clients to walk macro instantiations, if we ever care. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93915 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang-c/Index.h | 57 +++++++++++--- tools/CIndex/CIndex.cpp | 125 +++++++++++++++++++++++++----- tools/CIndex/CIndex.exports | 3 + tools/c-index-test/c-index-test.c | 41 +++++++--- 4 files changed, 185 insertions(+), 41 deletions(-) diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 0cf2d2b785..022d5bb479 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -333,27 +333,62 @@ CINDEX_LINKAGE const char *clang_getDeclSource(CXDecl); /* deprecate */ CINDEX_LINKAGE CXFile clang_getDeclSourceFile(CXDecl); /* deprecate */ /** - * \brief Identifies a specific source location given its file, line, and - * column. + * \brief Identifies a specific source location within a translation + * unit. + * + * Use clang_getInstantiationLocation() to map a source location to a + * particular file, line, and column. */ typedef struct { - CXFile file; - unsigned line; - unsigned column; + void *ptr_data; + unsigned int_data; } CXSourceLocation; /** - * \brief Identifies a range of source locations identified by the starting and - * ending locations of that range. + * \brief Identifies a range of source locations in the source code. * - * The \c begin location points to the first character in the range and the - * \c end location points to the last character in the range. + * Use clang_getRangeStart() and clang_getRangeEnd() to retrieve the + * starting and end locations from a source range, respectively. */ typedef struct { - CXSourceLocation begin; - CXSourceLocation end; + void *ptr_data; + unsigned begin_int_data; + unsigned end_int_data; } CXSourceRange; +/** + * \brief Retrieve the file, line, and column represented by the + * given source location. + * + * \param location the location within a source file that will be + * decomposed into its parts. + * + * \param file if non-NULL, will be set to the file to which the given + * source location points. + * + * \param line if non-NULL, will be set to the line to which the given + * source location points. + * + * \param column if non-NULL, will be set to the column to which the + * given source location points. + */ +CINDEX_LINKAGE void clang_getInstantiationLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column); + +/** + * \brief Retrieve a source location representing the first + * character within a source range. + */ +CINDEX_LINKAGE CXSourceLocation clang_getRangeStart(CXSourceRange range); + +/** + * \brief Retrieve a source location representing the last + * character within a source range. + */ +CINDEX_LINKAGE CXSourceLocation clang_getRangeEnd(CXSourceRange range); + /* clang_getDeclExtent() returns the physical extent of a declaration. The * beginning line/column pair points to the start of the first token in the * declaration, and the ending line/column pair points to the last character in diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index e6b4bafc33..a7cbb8a4fc 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -113,9 +113,17 @@ public: #endif #endif +typedef llvm::PointerIntPair CXSourceLocationPtr; + /// \brief Translate a Clang source location into a CIndex source location. -static CXSourceLocation translateSourceLocation(SourceManager &SourceMgr, - SourceLocation Loc) { +static CXSourceLocation translateSourceLocation(ASTContext &Context, + SourceLocation Loc, + bool AtEnd = false) { + CXSourceLocationPtr Ptr(&Context, AtEnd); + CXSourceLocation Result = { Ptr.getOpaqueValue(), Loc.getRawEncoding() }; + return Result; + +#if 0 SourceLocation InstLoc = SourceMgr.getInstantiationLoc(Loc); if (InstLoc.isInvalid()) { CXSourceLocation Loc = { 0, 0, 0 }; @@ -128,11 +136,16 @@ static CXSourceLocation translateSourceLocation(SourceManager &SourceMgr, Result.line = SourceMgr.getInstantiationLineNumber(InstLoc); Result.column = SourceMgr.getInstantiationColumnNumber(InstLoc); return Result; +#endif } /// \brief Translate a Clang source range into a CIndex source range. -static CXSourceRange translateSourceRange(ASTContext &Context, - SourceRange R) { +static CXSourceRange translateSourceRange(ASTContext &Context, SourceRange R) { + CXSourceRange Result = { &Context, + R.getBegin().getRawEncoding(), + R.getEnd().getRawEncoding() }; + return Result; +#if 0 if (R.isInvalid()) { CXSourceRange extent = { { 0, 0, 0 }, { 0, 0, 0 } }; return extent; @@ -177,8 +190,10 @@ static CXSourceRange translateSourceRange(ASTContext &Context, CXSourceRange extent = { { (void *)BeginFile, StartLineNo, StartColNo }, { (void *)EndFile, EndLineNo, EndColNo } }; return extent; +#endif } + //===----------------------------------------------------------------------===// // Visitors. //===----------------------------------------------------------------------===// @@ -606,6 +621,80 @@ void clang_loadDeclaration(CXDecl Dcl, } } // end: extern "C" +//===----------------------------------------------------------------------===// +// CXSourceLocation and CXSourceRange Operations. +//===----------------------------------------------------------------------===// + +void clang_getInstantiationLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column) { + CXSourceLocationPtr Ptr + = CXSourceLocationPtr::getFromOpaqueValue(location.ptr_data); + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + + if (!Ptr.getPointer() || Loc.isInvalid()) { + if (file) + *file = 0; + if (line) + *line = 0; + if (column) + *column = 0; + return; + } + + // FIXME: This is largely copy-paste from + ///TextDiagnosticPrinter::HighlightRange. When it is clear that this is + // what we want the two routines should be refactored. + ASTContext &Context = *Ptr.getPointer(); + SourceManager &SM = Context.getSourceManager(); + SourceLocation InstLoc = SM.getInstantiationLoc(Loc); + + if (Ptr.getInt()) { + // We want the last character in this location, so we will adjust + // the instantiation location accordingly. + + // If the location is from a macro instantiation, get the end of + // the instantiation range. + if (Loc.isMacroID()) + InstLoc = SM.getInstantiationRange(Loc).second; + + // Measure the length token we're pointing at, so we can adjust + // the physical location in the file to point at the last + // character. + // FIXME: This won't cope with trigraphs or escaped newlines + // well. For that, we actually need a preprocessor, which isn't + // currently available here. Eventually, we'll switch the pointer + // data of CXSourceLocation/CXSourceRange to a translation unit + // (CXXUnit), so that the preprocessor will be available here. At + // that point, we can use Preprocessor::getLocForEndOfToken(). + unsigned Length = Lexer::MeasureTokenLength(InstLoc, SM, + Context.getLangOptions()); + if (Length > 0) + InstLoc = InstLoc.getFileLocWithOffset(Length - 1); + } + + if (file) + *file = (void *)SM.getFileEntryForID(SM.getFileID(InstLoc)); + if (line) + *line = SM.getInstantiationLineNumber(InstLoc); + if (column) + *column = SM.getInstantiationColumnNumber(InstLoc); +} + +CXSourceLocation clang_getRangeStart(CXSourceRange range) { + CXSourceLocation Result = { range.ptr_data, range.begin_int_data }; + return Result; +} + +CXSourceLocation clang_getRangeEnd(CXSourceRange range) { + llvm::PointerIntPair Ptr; + Ptr.setPointer(static_cast(range.ptr_data)); + Ptr.setInt(true); + CXSourceLocation Result = { Ptr.getOpaqueValue(), range.end_int_data }; + return Result; +} + //===----------------------------------------------------------------------===// // CXDecl Operations. //===----------------------------------------------------------------------===// @@ -896,22 +985,19 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { case CXCursor_ObjCSuperClassRef: { std::pair P = getCursorObjCSuperClassRef(C); - SourceManager &SM = P.first->getASTContext().getSourceManager(); - return translateSourceLocation(SM, P.second); + return translateSourceLocation(P.first->getASTContext(), P.second); } case CXCursor_ObjCProtocolRef: { std::pair P = getCursorObjCProtocolRef(C); - SourceManager &SM = P.first->getASTContext().getSourceManager(); - return translateSourceLocation(SM, P.second); + return translateSourceLocation(P.first->getASTContext(), P.second); } case CXCursor_ObjCClassRef: { std::pair P = getCursorObjCClassRef(C); - SourceManager &SM = P.first->getASTContext().getSourceManager(); - return translateSourceLocation(SM, P.second); + return translateSourceLocation(P.first->getASTContext(), P.second); } case CXCursor_ObjCSelectorRef: @@ -921,16 +1007,16 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { case CXCursor_EnumConstantRef: case CXCursor_MemberRef: { Expr *E = getCursorExpr(C); - SourceManager &SM = getCursorContext(C).getSourceManager(); + ASTContext &Context = getCursorContext(C); if (ObjCMessageExpr *Msg = dyn_cast(E)) - return translateSourceLocation(SM, /*FIXME:*/Msg->getLeftLoc()); + return translateSourceLocation(Context, /*FIXME:*/Msg->getLeftLoc()); if (DeclRefExpr *DRE = dyn_cast(E)) - return translateSourceLocation(SM, DRE->getLocation()); + return translateSourceLocation(Context, DRE->getLocation()); if (MemberExpr *Member = dyn_cast(E)) - return translateSourceLocation(SM, Member->getMemberLoc()); + return translateSourceLocation(Context, Member->getMemberLoc()); if (ObjCIvarRefExpr *Ivar = dyn_cast(E)) - return translateSourceLocation(SM, Ivar->getLocation()); - return translateSourceLocation(SM, E->getLocStart()); + return translateSourceLocation(Context, Ivar->getLocation()); + return translateSourceLocation(Context, E->getLocStart()); } default: @@ -940,16 +1026,15 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { } if (!getCursorDecl(C)) { - CXSourceLocation empty = { 0, 0, 0 }; + CXSourceLocation empty = { 0, 0 }; return empty; } Decl *D = getCursorDecl(C); - SourceManager &SM = D->getASTContext().getSourceManager(); SourceLocation Loc = D->getLocation(); if (ObjCInterfaceDecl *Class = dyn_cast(D)) Loc = Class->getClassLoc(); - return translateSourceLocation(SM, Loc); + return translateSourceLocation(D->getASTContext(), Loc); } CXSourceRange clang_getCursorExtent(CXCursor C) { @@ -990,7 +1075,7 @@ CXSourceRange clang_getCursorExtent(CXCursor C) { } if (!getCursorDecl(C)) { - CXSourceRange empty = { { 0, 0, 0 }, { 0, 0, 0 } }; + CXSourceRange empty = { 0, 0, 0 }; return empty; } diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports index 0460ba0d59..3de081d38e 100644 --- a/tools/CIndex/CIndex.exports +++ b/tools/CIndex/CIndex.exports @@ -34,8 +34,11 @@ _clang_getDefinitionSpellingAndExtent _clang_getEntityFromDecl _clang_getFileName _clang_getFileTime +_clang_getInstantiationLocation _clang_getNullCursor _clang_getNumCompletionChunks +_clang_getRangeEnd +_clang_getRangeStart _clang_getTranslationUnitSpelling _clang_isCursorDefinition _clang_isDeclaration diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 391f577bc4..2d4ebf4406 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -49,6 +49,7 @@ static void PrintCursor(CXCursor Cursor) { else { CXString string; CXCursor Referenced; + unsigned line, column; string = clang_getCursorSpelling(Cursor); printf("%s=%s", clang_getCursorKindSpelling(Cursor.kind), clang_getCString(string)); @@ -57,7 +58,8 @@ static void PrintCursor(CXCursor Cursor) { Referenced = clang_getCursorReferenced(Cursor); if (!clang_equalCursors(Referenced, clang_getNullCursor())) { CXSourceLocation Loc = clang_getCursorLocation(Referenced); - printf(":%d:%d", Loc.line, Loc.column); + clang_getInstantiationLocation(Loc, 0, &line, &column); + printf(":%d:%d", line, column); } if (clang_isCursorDefinition(Cursor)) @@ -66,7 +68,11 @@ static void PrintCursor(CXCursor Cursor) { } static const char* GetCursorSource(CXCursor Cursor) { - const char *source = clang_getFileName(clang_getCursorLocation(Cursor).file); + CXSourceLocation Loc = clang_getCursorLocation(Cursor); + const char *source; + CXFile file; + clang_getInstantiationLocation(Loc, &file, 0, 0); + source = clang_getFileName(file); if (!source) return ""; return basename(source); @@ -80,20 +86,31 @@ static const char *FileCheckPrefix = "CHECK"; static void PrintCursorExtent(CXCursor C) { CXSourceRange extent = clang_getCursorExtent(C); - /* FIXME: Better way to check for empty extents? */ - if (!extent.begin.file) + CXFile begin_file, end_file; + unsigned begin_line, begin_column, end_line, end_column; + + clang_getInstantiationLocation(clang_getRangeStart(extent), + &begin_file, &begin_line, &begin_column); + clang_getInstantiationLocation(clang_getRangeEnd(extent), + &end_file, &end_line, &end_column); + if (!begin_file || !end_file) return; - printf(" [Extent=%d:%d:%d:%d]", extent.begin.line, extent.begin.column, - extent.end.line, extent.end.column); + + printf(" [Extent=%d:%d:%d:%d]", begin_line, begin_column, + end_line, end_column); } static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter) { if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) { CXSourceLocation Loc = clang_getCursorLocation(Cursor); - const char *source = clang_getFileName(Loc.file); + CXFile file; + unsigned line, column; + const char *source; + clang_getInstantiationLocation(Loc, &file, &line, &column); + source = clang_getFileName(file); if (!source) source = ""; - printf("// %s: %s:%d:%d: ", FileCheckPrefix, source, Loc.line, Loc.column); + printf("// %s: %s:%d:%d: ", FileCheckPrefix, source, line, column); PrintCursor(Cursor); PrintCursorExtent(Cursor); @@ -106,8 +123,10 @@ static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor, if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) { CXDecl D; CXSourceLocation Loc = clang_getCursorLocation(Cursor); + unsigned line, column; + clang_getInstantiationLocation(Loc, 0, &line, &column); printf("// %s: %s:%d:%d: ", FileCheckPrefix, - GetCursorSource(Cursor), Loc.line, Loc.column); + GetCursorSource(Cursor), line, column); PrintCursor(Cursor); D = clang_getCursorDecl(Cursor); @@ -141,6 +160,7 @@ static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor, while (startBuf < endBuf) { CXSourceLocation Loc; + CXFile file; const char *source = 0; if (*startBuf == '\n') { @@ -151,7 +171,8 @@ static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor, curColumn++; Loc = clang_getCursorLocation(Cursor); - source = clang_getFileName(Loc.file); + clang_getInstantiationLocation(Loc, &file, 0, 0); + source = clang_getFileName(file); if (source) { Ref = clang_getCursor(Unit, source, curLine, curColumn); if (Ref.kind == CXCursor_NoDeclFound) { -- 2.50.1