From d289104e292162c9a7b5094942aadfd855a34d3a Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Mon, 27 Jun 2011 19:42:23 +0000 Subject: [PATCH] [libclang] Avoid having the cursor of an expression replace the declaration cursor when the expression source range overlaps the declaration range. This can happen for C++ constructor expressions whose range generally include the variable declaration, e.g.: MyCXXClass foo; // Make sure pointing at 'foo' returns a VarDecl cursor. rdar://9124499. llvm-svn: 133930 --- clang/test/Index/get-cursor.cpp | 7 +++++++ clang/tools/libclang/CIndex.cpp | 30 +++++++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/clang/test/Index/get-cursor.cpp b/clang/test/Index/get-cursor.cpp index f26d9825a102..2aa76c472569 100644 --- a/clang/test/Index/get-cursor.cpp +++ b/clang/test/Index/get-cursor.cpp @@ -31,6 +31,10 @@ struct YDerived : Y { X getAnotherX() { return member; } }; +void test() { + X foo; +} + // RUN: c-index-test -cursor-at=%s:12:20 %s | FileCheck -check-prefix=CHECK-VALUE-REF %s // RUN: c-index-test -cursor-at=%s:13:21 %s | FileCheck -check-prefix=CHECK-VALUE-REF %s // RUN: c-index-test -cursor-at=%s:13:28 %s | FileCheck -check-prefix=CHECK-VALUE-REF %s @@ -61,3 +65,6 @@ struct YDerived : Y { // RUN: c-index-test -cursor-at=%s:27:10 %s | FileCheck -check-prefix=CHECK-IMPLICIT-MEMREF %s // RUN: c-index-test -cursor-at=%s:31:28 %s | FileCheck -check-prefix=CHECK-IMPLICIT-MEMREF %s // CHECK-IMPLICIT-MEMREF: MemberRefExpr=member:21:7 + +// RUN: c-index-test -cursor-at=%s:35:5 %s | FileCheck -check-prefix=CHECK-DECL %s +// CHECK-DECL: VarDecl=foo:35:5 diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 3acf8908a0f1..49b02c4bdfc6 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -3393,11 +3393,34 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString((const char*) 0); } +struct GetCursorData { + SourceLocation TokenBeginLoc; + CXCursor &BestCursor; + + GetCursorData(SourceLocation tokenBegin, CXCursor &outputCursor) + : TokenBeginLoc(tokenBegin), BestCursor(outputCursor) { } +}; + enum CXChildVisitResult GetCursorVisitor(CXCursor cursor, CXCursor parent, CXClientData client_data) { - CXCursor *BestCursor = static_cast(client_data); - + GetCursorData *Data = static_cast(client_data); + CXCursor *BestCursor = &Data->BestCursor; + + if (clang_isExpression(cursor.kind) && + clang_isDeclaration(BestCursor->kind)) { + Decl *D = getCursorDecl(*BestCursor); + + // Avoid having the cursor of an expression replace the declaration cursor + // when the expression source range overlaps the declaration range. + // This can happen for C++ constructor expressions whose range generally + // include the variable declaration, e.g.: + // MyCXXClass foo; // Make sure pointing at 'foo' returns a VarDecl cursor. + if (D->getLocation().isValid() && Data->TokenBeginLoc.isValid() && + D->getLocation() == Data->TokenBeginLoc) + return CXChildVisit_Break; + } + // If our current best cursor is the construction of a temporary object, // don't replace that cursor with a type reference, because we want // clang_getCursor() to point at the constructor. @@ -3441,8 +3464,9 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) { // 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. + GetCursorData ResultData(SLoc, Result); CXCursor Parent = clang_getTranslationUnitCursor(TU); - CursorVisitor CursorVis(TU, GetCursorVisitor, &Result, + CursorVisitor CursorVis(TU, GetCursorVisitor, &ResultData, Decl::MaxPCHLevel, true, SourceLocation(SLoc)); CursorVis.VisitChildren(Parent); }