From: Douglas Gregor Date: Thu, 9 Sep 2010 21:42:20 +0000 (+0000) Subject: Teach libclang to walk the base and member initializers of a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a67e03fdf1ae8a1f92463a307d0b6281f1161f40;p=clang Teach libclang to walk the base and member initializers of a constructor, in source order. Also introduces a new reference kind for class members, which is used here (for member initializers) and will also be used for designated initializers and offsetof. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@113545 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 4631c65bf0..fb742078f4 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -1027,15 +1027,20 @@ enum CXCursorKind { CXCursor_TypeRef = 43, CXCursor_CXXBaseSpecifier = 44, /** - * \brief A reference to a class template, function template, or template - * template parameter. + * \brief A reference to a class template, function template, template + * template parameter, or class template partial specialization. */ CXCursor_TemplateRef = 45, /** * \brief A reference to a namespace or namespace alias. */ CXCursor_NamespaceRef = 46, - CXCursor_LastRef = CXCursor_NamespaceRef, + /** + * A reference to a member of a struct, union, or class that occurs in some + * non-expression context, e.g., a designated initializer. + */ + CXCursor_MemberRef = 47, + CXCursor_LastRef = CXCursor_MemberRef, /* Error conditions */ CXCursor_FirstInvalid = 70, diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index d8c2c4ff20..135c59365b 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -3438,7 +3438,8 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, Pattern->AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(CodeCompletionResult(Pattern, SawLastInitializer? CCP_NextInitializer - : CCP_MemberDeclaration)); + : CCP_MemberDeclaration, + CXCursor_MemberRef)); SawLastInitializer = false; } Results.ExitScope(); diff --git a/test/Index/complete-ctor-inits.cpp b/test/Index/complete-ctor-inits.cpp index f9cc7022ea..b926f785d8 100644 --- a/test/Index/complete-ctor-inits.cpp +++ b/test/Index/complete-ctor-inits.cpp @@ -18,23 +18,23 @@ struct Z : public X, public Y { Z::Z() : ::X(0), Virt(), b(), c() { } // RUN: c-index-test -code-completion-at=%s:18:10 %s | FileCheck -check-prefix=CHECK-CC1 %s -// CHECK-CC1: NotImplemented:{TypedText a}{LeftParen (}{Placeholder args}{RightParen )} (20) -// CHECK-CC1: NotImplemented:{TypedText b}{LeftParen (}{Placeholder args}{RightParen )} (20) -// CHECK-CC1: NotImplemented:{TypedText c}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC1: MemberRef:{TypedText a}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC1: MemberRef:{TypedText b}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC1: MemberRef:{TypedText c}{LeftParen (}{Placeholder args}{RightParen )} (20) // CHECK-CC1: NotImplemented:{TypedText Virt}{LeftParen (}{Placeholder args}{RightParen )} (20) // CHECK-CC1: NotImplemented:{TypedText X}{LeftParen (}{Placeholder args}{RightParen )} (7) // CHECK-CC1: NotImplemented:{TypedText Y}{LeftParen (}{Placeholder args}{RightParen )} (20) // RUN: c-index-test -code-completion-at=%s:18:23 %s | FileCheck -check-prefix=CHECK-CC2 %s -// CHECK-CC2: NotImplemented:{TypedText a}{LeftParen (}{Placeholder args}{RightParen )} (20) -// CHECK-CC2: NotImplemented:{TypedText b}{LeftParen (}{Placeholder args}{RightParen )} (20) -// CHECK-CC2: NotImplemented:{TypedText c}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC2: MemberRef:{TypedText a}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC2: MemberRef:{TypedText b}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC2: MemberRef:{TypedText c}{LeftParen (}{Placeholder args}{RightParen )} (20) // CHECK-CC2: NotImplemented:{TypedText Virt}{LeftParen (}{Placeholder args}{RightParen )} (20) // CHECK-CC2: NotImplemented:{TypedText Y}{LeftParen (}{Placeholder args}{RightParen )} (7) // RUN: c-index-test -code-completion-at=%s:18:36 %s | FileCheck -check-prefix=CHECK-CC3 %s -// CHECK-CC3: NotImplemented:{TypedText a}{LeftParen (}{Placeholder args}{RightParen )} (20) -// CHECK-CC3-NOT: NotImplemented:{TypedText b}{LeftParen (}{Placeholder args}{RightParen )} -// CHECK-CC3: NotImplemented:{TypedText c}{LeftParen (}{Placeholder args}{RightParen )} (7) +// CHECK-CC3: MemberRef:{TypedText a}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC3-NOT: MemberRef:{TypedText b}{LeftParen (}{Placeholder args}{RightParen )} +// CHECK-CC3: MemberRef:{TypedText c}{LeftParen (}{Placeholder args}{RightParen )} (7) // CHECK-CC3-NOT: NotImplemented:{TypedText Virt}{LeftParen (}{Placeholder args}{RightParen )} // CHECK-CC3: NotImplemented:{TypedText Y}{LeftParen (}{Placeholder args}{RightParen )} (20) diff --git a/test/Index/load-stmts.cpp b/test/Index/load-stmts.cpp index 81d506519e..d101092937 100644 --- a/test/Index/load-stmts.cpp +++ b/test/Index/load-stmts.cpp @@ -91,6 +91,19 @@ void test_even_more_dependent_exprs(T t, Y y) { (void)__has_nothrow_assign(type); } +struct Base { + Base(int); +}; + +struct Derived : public Base { + Derived(int x); + int member; +}; + +Derived::Derived(int x) + : member(x), Base(x) { +} + // RUN: c-index-test -test-load-source all %s | FileCheck %s // CHECK: load-stmts.cpp:1:13: TypedefDecl=T:1:13 (Definition) Extent=[1:13 - 1:14] // CHECK: load-stmts.cpp:2:8: StructDecl=X:2:8 (Definition) Extent=[2:1 - 2:23] @@ -198,3 +211,12 @@ void test_even_more_dependent_exprs(T t, Y y) { // CHECK: load-stmts.cpp:90:17: DeclRefExpr=y:88:44 Extent=[90:17 - 90:18] // CHECK: load-stmts.cpp:91:9: UnexposedExpr= Extent=[91:9 - 91:35] // CHECK: load-stmts.cpp:91:30: TypeRef=type:89:13 Extent=[91:30 - 91:34] +// CHECK: load-stmts.cpp:103:10: CXXConstructor=Derived:103:10 (Definition) +// CHECK: load-stmts.cpp:103:1: TypeRef=struct Derived:98:8 Extent=[103:1 - 103: +// FIXME: Missing TypeRef for constructor name. +// CHECK: load-stmts.cpp:103:22: ParmDecl=x:103:22 (Definition) +// CHECK: load-stmts.cpp:104:5: MemberRef=member:100:7 Extent=[104:5 - 104:11] +// CHECK: load-stmts.cpp:104:12: DeclRefExpr=x:103:22 Extent=[104:12 - 104:13] +// CHECK: load-stmts.cpp:104:16: TypeRef=struct Base:94:8 Extent=[104:16 - 104:2 +// CHECK: load-stmts.cpp:104:16: CallExpr= Extent=[104:16 - 104:22] +// CHECK: load-stmts.cpp:104:21: DeclRefExpr=x:103:22 Extent=[104:21 - 104:22] diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 5a3084c49b..cb2f7b53dc 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -30,6 +30,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Timer.h" @@ -697,6 +698,21 @@ bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) { return false; } +/// \brief Compare two base or member initializers based on their source order. +static int CompareCXXBaseOrMemberInitializers(const void* Xp, const void *Yp) { + CXXBaseOrMemberInitializer const * const *X + = static_cast(Xp); + CXXBaseOrMemberInitializer const * const *Y + = static_cast(Yp); + + if ((*X)->getSourceOrder() < (*Y)->getSourceOrder()) + return -1; + else if ((*X)->getSourceOrder() > (*Y)->getSourceOrder()) + return 1; + else + return 0; +} + bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) { if (TypeSourceInfo *TSInfo = ND->getTypeSourceInfo()) { // Visit the function declaration's syntactic components in the order @@ -729,9 +745,45 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) { // FIXME: Attributes? } - if (ND->isThisDeclarationADefinition() && - Visit(MakeCXCursor(ND->getBody(), StmtParent, TU))) - return true; + if (ND->isThisDeclarationADefinition()) { + if (CXXConstructorDecl *Constructor = dyn_cast(ND)) { + // Find the initializers that were written in the source. + llvm::SmallVector WrittenInits; + for (CXXConstructorDecl::init_iterator I = Constructor->init_begin(), + IEnd = Constructor->init_end(); + I != IEnd; ++I) { + if (!(*I)->isWritten()) + continue; + + WrittenInits.push_back(*I); + } + + // Sort the initializers in source order + llvm::array_pod_sort(WrittenInits.begin(), WrittenInits.end(), + &CompareCXXBaseOrMemberInitializers); + + // Visit the initializers in source order + for (unsigned I = 0, N = WrittenInits.size(); I != N; ++I) { + CXXBaseOrMemberInitializer *Init = WrittenInits[I]; + if (Init->isMemberInitializer()) { + if (Visit(MakeCursorMemberRef(Init->getMember(), + Init->getMemberLocation(), TU))) + return true; + } else if (TypeSourceInfo *BaseInfo = Init->getBaseClassInfo()) { + if (Visit(BaseInfo->getTypeLoc())) + return true; + } + + // Visit the initializer value. + if (Expr *Initializer = Init->getInit()) + if (Visit(MakeCXCursor(Initializer, ND, TU))) + return true; + } + } + + if (Visit(MakeCXCursor(ND->getBody(), StmtParent, TU))) + return true; + } return false; } @@ -2485,6 +2537,13 @@ CXString clang_getCursorSpelling(CXCursor C) { return createCXString(NS->getNameAsString()); } + case CXCursor_MemberRef: { + FieldDecl *Field = getCursorMemberRef(C).first; + assert(Field && "Missing member decl"); + + return createCXString(Field->getNameAsString()); + } + default: return createCXString(""); } @@ -2567,6 +2626,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString("TemplateRef"); case CXCursor_NamespaceRef: return createCXString("NamespaceRef"); + case CXCursor_MemberRef: + return createCXString("MemberRef"); case CXCursor_UnexposedExpr: return createCXString("UnexposedExpr"); case CXCursor_BlockExpr: @@ -2769,6 +2830,11 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); } + case CXCursor_MemberRef: { + std::pair P = getCursorMemberRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + case CXCursor_CXXBaseSpecifier: { // FIXME: Figure out what location to return for a CXXBaseSpecifier. return clang_getNullLocation(); @@ -2832,7 +2898,10 @@ static SourceRange getRawCursorExtent(CXCursor C) { case CXCursor_NamespaceRef: return getCursorNamespaceRef(C).second; - + + case CXCursor_MemberRef: + return getCursorMemberRef(C).second; + case CXCursor_CXXBaseSpecifier: // FIXME: Figure out what source range to use for a CXBaseSpecifier. return SourceRange(); @@ -2916,6 +2985,9 @@ CXCursor clang_getCursorReferenced(CXCursor C) { case CXCursor_NamespaceRef: return MakeCXCursor(getCursorNamespaceRef(C).first, CXXUnit); + case CXCursor_MemberRef: + return MakeCXCursor(getCursorMemberRef(C).first, CXXUnit); + case CXCursor_CXXBaseSpecifier: { CXXBaseSpecifier *B = cxcursor::getCursorCXXBaseSpecifier(C); return clang_getTypeDeclaration(cxtype::MakeCXType(B->getType(), diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 9b3ecbf0d9..53145a6719 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -291,6 +291,23 @@ cxcursor::getCursorNamespaceRef(CXCursor C) { reinterpret_cast(C.data[1]))); } +CXCursor cxcursor::MakeCursorMemberRef(FieldDecl *Field, SourceLocation Loc, + ASTUnit *TU) { + + assert(Field && TU && "Invalid arguments!"); + void *RawLoc = reinterpret_cast(Loc.getRawEncoding()); + CXCursor C = { CXCursor_MemberRef, { Field, RawLoc, TU } }; + return C; +} + +std::pair +cxcursor::getCursorMemberRef(CXCursor C) { + assert(C.kind == CXCursor_MemberRef); + return std::make_pair(static_cast(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast(C.data[1]))); +} + CXCursor cxcursor::MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B, ASTUnit *TU){ CXCursor C = { CXCursor_CXXBaseSpecifier, { B, 0, TU } }; return C; diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h index a5f111edc1..eff71f398a 100644 --- a/tools/libclang/CXCursor.h +++ b/tools/libclang/CXCursor.h @@ -26,6 +26,7 @@ class Attr; class CXXBaseSpecifier; class Decl; class Expr; +class FieldDecl; class MacroDefinition; class MacroInstantiation; class NamedDecl; @@ -93,6 +94,14 @@ CXCursor MakeCursorNamespaceRef(NamedDecl *NS, SourceLocation Loc, ASTUnit *TU); /// it references and the location where the reference occurred. std::pair getCursorNamespaceRef(CXCursor C); +/// \brief Create a reference to a field at the given location. +CXCursor MakeCursorMemberRef(FieldDecl *Field, SourceLocation Loc, + ASTUnit *TU); + +/// \brief Unpack a MemberRef cursor into the field it references and the +/// location where the reference occurred. +std::pair getCursorMemberRef(CXCursor C); + /// \brief Create a CXX base specifier cursor. CXCursor MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B, ASTUnit *TU);