diff options
-rw-r--r-- | include/clang/Lex/Lexer.h | 9 | ||||
-rw-r--r-- | lib/Lex/Lexer.cpp | 53 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 113 |
3 files changed, 113 insertions, 62 deletions
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h index 96d7605e4d..8dd37d0348 100644 --- a/include/clang/Lex/Lexer.h +++ b/include/clang/Lex/Lexer.h @@ -219,6 +219,15 @@ public: const SourceManager &SM, const LangOptions &LangOpts); + /// \brief Given a location any where in a source buffer, find the location + /// that corresponds to the beginning of the token in which the original + /// source location lands. + /// + /// \param Loc + static SourceLocation GetBeginningOfToken(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts); + /// \brief Compute the preamble of the given file. /// /// The preamble of a file contains the initial comments, include directives, diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 2f11c37e65..b23122cbcc 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -248,6 +248,59 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc, return TheTok.getLength(); } +SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts) { + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + bool Invalid = false; + llvm::StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return Loc; + + // Back up from the current location until we hit the beginning of a line + // (or the buffer). We'll relex from that point. + const char *BufStart = Buffer.data(); + const char *StrData = BufStart+LocInfo.second; + if (StrData[0] == '\n' || StrData[0] == '\r') + return Loc; + + const char *LexStart = StrData; + while (LexStart != BufStart) { + if (LexStart[0] == '\n' || LexStart[0] == '\r') { + ++LexStart; + break; + } + + --LexStart; + } + + // Create a lexer starting at the beginning of this token. + SourceLocation LexerStartLoc = Loc.getFileLocWithOffset(-LocInfo.second); + Lexer TheLexer(LexerStartLoc, LangOpts, BufStart, LexStart, Buffer.end()); + TheLexer.SetCommentRetentionState(true); + + // Lex tokens until we find the token that contains the source location. + Token TheTok; + do { + TheLexer.LexFromRawLexer(TheTok); + + if (TheLexer.getBufferLocation() > StrData) { + // Lexing this token has taken the lexer past the source location we're + // looking for. If the current token encompasses our source location, + // return the beginning of that token. + if (TheLexer.getBufferLocation() - TheTok.getLength() <= StrData) + return TheTok.getLocation(); + + // We ended up skipping over the source location entirely, which means + // that it points into whitespace. We're done here. + break; + } + } while (TheTok.getKind() != tok::eof); + + // We've passed our source location; just return the original source location. + return Loc; +} + namespace { enum PreambleDirectiveKind { PDK_Skipped, diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 0a3d54b6cb..51965bb8a1 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -143,10 +143,10 @@ static RangeComparisonResult RangeCompare(SourceManager &SM, SourceRange R2) { assert(R1.isValid() && "First range is invalid?"); assert(R2.isValid() && "Second range is invalid?"); - if (R1.getEnd() == R2.getBegin() || + if (R1.getEnd() != R2.getBegin() && SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin())) return RangeBefore; - if (R2.getEnd() == R1.getBegin() || + if (R2.getEnd() != R1.getBegin() && SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin())) return RangeAfter; return RangeOverlap; @@ -158,10 +158,8 @@ static RangeComparisonResult LocationCompare(SourceManager &SM, SourceLocation L, SourceRange R) { assert(R.isValid() && "First range is invalid?"); assert(L.isValid() && "Second range is invalid?"); - if (L == R.getBegin()) + if (L == R.getBegin() || L == R.getEnd()) return RangeOverlap; - if (L == R.getEnd()) - return RangeAfter; if (SM.isBeforeInTranslationUnit(L, R.getBegin())) return RangeBefore; if (SM.isBeforeInTranslationUnit(R.getEnd(), L)) @@ -356,6 +354,8 @@ public: } // end anonymous namespace +static SourceRange getRawCursorExtent(CXCursor C); + RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) { return RangeCompare(TU->getSourceManager(), R, RegionOfInterest); } @@ -387,8 +387,7 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) { // If we have a range of interest, and this cursor doesn't intersect with it, // we're done. if (RegionOfInterest.isValid() && !CheckedRegionOfInterest) { - SourceRange Range = - cxloc::translateCXSourceRange(clang_getCursorExtent(Cursor)); + SourceRange Range = getRawCursorExtent(Cursor); if (Range.isInvalid() || CompareRegionOfInterest(Range)) return false; } @@ -537,8 +536,7 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) { CXCursor Cursor = MakeCXCursor(D, TU); if (RegionOfInterest.isValid()) { - SourceRange Range = - cxloc::translateCXSourceRange(clang_getCursorExtent(Cursor)); + SourceRange Range = getRawCursorExtent(Cursor); if (Range.isInvalid()) continue; @@ -1817,17 +1815,20 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) { ASTUnit::ConcurrencyCheck Check(*CXXUnit); + // Translate the given source location to make it point at the beginning of + // the token under the cursor. SourceLocation SLoc = cxloc::translateSourceLocation(Loc); + SLoc = Lexer::GetBeginningOfToken(SLoc, CXXUnit->getSourceManager(), + CXXUnit->getASTContext().getLangOptions()); + CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound); if (SLoc.isValid()) { - SourceRange RegionOfInterest(SLoc, SLoc.getFileLocWithOffset(1)); - // FIXME: Would be great to have a "hint" cursor, then walk from that // hint cursor upward until we find a cursor whose source range encloses // the region of interest, rather than starting from the translation unit. CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit); CursorVisitor CursorVis(CXXUnit, GetCursorVisitor, &Result, - Decl::MaxPCHLevel, RegionOfInterest); + Decl::MaxPCHLevel, SourceLocation(SLoc)); CursorVis.VisitChildren(Parent); } return Result; @@ -1947,67 +1948,58 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { return cxloc::translateSourceLocation(getCursorContext(C), Loc); } -CXSourceRange clang_getCursorExtent(CXCursor C) { +} // end extern "C" + +static SourceRange getRawCursorExtent(CXCursor C) { if (clang_isReference(C.kind)) { switch (C.kind) { - case CXCursor_ObjCSuperClassRef: { - std::pair<ObjCInterfaceDecl *, SourceLocation> P - = getCursorObjCSuperClassRef(C); - return cxloc::translateSourceRange(P.first->getASTContext(), P.second); - } - - case CXCursor_ObjCProtocolRef: { - std::pair<ObjCProtocolDecl *, SourceLocation> P - = getCursorObjCProtocolRef(C); - return cxloc::translateSourceRange(P.first->getASTContext(), P.second); - } + case CXCursor_ObjCSuperClassRef: + return getCursorObjCSuperClassRef(C).second; - case CXCursor_ObjCClassRef: { - std::pair<ObjCInterfaceDecl *, SourceLocation> P - = getCursorObjCClassRef(C); + case CXCursor_ObjCProtocolRef: + return getCursorObjCProtocolRef(C).second; - return cxloc::translateSourceRange(P.first->getASTContext(), P.second); - } + case CXCursor_ObjCClassRef: + return getCursorObjCClassRef(C).second; - case CXCursor_TypeRef: { - std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C); - return cxloc::translateSourceRange(P.first->getASTContext(), P.second); - } + case CXCursor_TypeRef: + return getCursorTypeRef(C).second; - default: - // FIXME: Need a way to enumerate all non-reference cases. - llvm_unreachable("Missed a reference kind"); + default: + // FIXME: Need a way to enumerate all non-reference cases. + llvm_unreachable("Missed a reference kind"); } } if (clang_isExpression(C.kind)) - return cxloc::translateSourceRange(getCursorContext(C), - getCursorExpr(C)->getSourceRange()); + return getCursorExpr(C)->getSourceRange(); if (clang_isStatement(C.kind)) - return cxloc::translateSourceRange(getCursorContext(C), - getCursorStmt(C)->getSourceRange()); + return getCursorStmt(C)->getSourceRange(); - if (C.kind == CXCursor_PreprocessingDirective) { - SourceRange R = cxcursor::getCursorPreprocessingDirective(C); - return cxloc::translateSourceRange(getCursorContext(C), R); - } + if (C.kind == CXCursor_PreprocessingDirective) + return cxcursor::getCursorPreprocessingDirective(C); - if (C.kind == CXCursor_MacroInstantiation) { - SourceRange R = cxcursor::getCursorMacroInstantiation(C)->getSourceRange(); - return cxloc::translateSourceRange(getCursorContext(C), R); - } + if (C.kind == CXCursor_MacroInstantiation) + return cxcursor::getCursorMacroInstantiation(C)->getSourceRange(); - if (C.kind == CXCursor_MacroDefinition) { - SourceRange R = cxcursor::getCursorMacroDefinition(C)->getSourceRange(); - return cxloc::translateSourceRange(getCursorContext(C), R); - } + if (C.kind == CXCursor_MacroDefinition) + return cxcursor::getCursorMacroDefinition(C)->getSourceRange(); - if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl) + if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) + return getCursorDecl(C)->getSourceRange(); + + return SourceRange(); +} + +extern "C" { + +CXSourceRange clang_getCursorExtent(CXCursor C) { + SourceRange R = getRawCursorExtent(C); + if (R.isInvalid()) return clang_getNullRange(); - Decl *D = getCursorDecl(C); - return cxloc::translateSourceRange(getCursorContext(C), D->getSourceRange()); + return cxloc::translateSourceRange(getCursorContext(C), R); } CXCursor clang_getCursorReferenced(CXCursor C) { @@ -2568,8 +2560,7 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { return CXChildVisit_Recurse; } - CXSourceRange cursorExtent = clang_getCursorExtent(cursor); - SourceRange cursorRange = cxloc::translateCXSourceRange(cursorExtent); + SourceRange cursorRange = getRawCursorExtent(cursor); if (cursorRange.isInvalid()) return CXChildVisit_Continue; @@ -2696,11 +2687,9 @@ void clang_annotateTokens(CXTranslationUnit TU, SourceRange RegionOfInterest; RegionOfInterest.setBegin(cxloc::translateSourceLocation( clang_getTokenLocation(TU, Tokens[0]))); - - SourceLocation End - = cxloc::translateSourceLocation(clang_getTokenLocation(TU, - Tokens[NumTokens - 1])); - RegionOfInterest.setEnd(CXXUnit->getPreprocessor().getLocForEndOfToken(End)); + RegionOfInterest.setEnd(cxloc::translateSourceLocation( + clang_getTokenLocation(TU, + Tokens[NumTokens - 1]))); // A mapping from the source locations found when re-lexing or traversing the // region of interest to the corresponding cursors. |