forked from OSchip/llvm-project
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. llvm-svn: 113545
This commit is contained in:
parent
7ce4686958
commit
f3af311382
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -18,23 +18,23 @@ struct Z : public X<int>, public Y {
|
|||
Z::Z() : ::X<int>(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<int>}{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)
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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<CXXBaseOrMemberInitializer const * const *>(Xp);
|
||||
CXXBaseOrMemberInitializer const * const *Y
|
||||
= static_cast<CXXBaseOrMemberInitializer const * const *>(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<CXXConstructorDecl>(ND)) {
|
||||
// Find the initializers that were written in the source.
|
||||
llvm::SmallVector<CXXBaseOrMemberInitializer *, 4> 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("<not implemented>");
|
||||
}
|
||||
|
@ -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<FieldDecl *, SourceLocation> 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(),
|
||||
|
|
|
@ -291,6 +291,23 @@ cxcursor::getCursorNamespaceRef(CXCursor C) {
|
|||
reinterpret_cast<uintptr_t>(C.data[1])));
|
||||
}
|
||||
|
||||
CXCursor cxcursor::MakeCursorMemberRef(FieldDecl *Field, SourceLocation Loc,
|
||||
ASTUnit *TU) {
|
||||
|
||||
assert(Field && TU && "Invalid arguments!");
|
||||
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
|
||||
CXCursor C = { CXCursor_MemberRef, { Field, RawLoc, TU } };
|
||||
return C;
|
||||
}
|
||||
|
||||
std::pair<FieldDecl *, SourceLocation>
|
||||
cxcursor::getCursorMemberRef(CXCursor C) {
|
||||
assert(C.kind == CXCursor_MemberRef);
|
||||
return std::make_pair(static_cast<FieldDecl *>(C.data[0]),
|
||||
SourceLocation::getFromRawEncoding(
|
||||
reinterpret_cast<uintptr_t>(C.data[1])));
|
||||
}
|
||||
|
||||
CXCursor cxcursor::MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B, ASTUnit *TU){
|
||||
CXCursor C = { CXCursor_CXXBaseSpecifier, { B, 0, TU } };
|
||||
return C;
|
||||
|
|
|
@ -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<NamedDecl *, SourceLocation> 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<FieldDecl *, SourceLocation> getCursorMemberRef(CXCursor C);
|
||||
|
||||
/// \brief Create a CXX base specifier cursor.
|
||||
CXCursor MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B, ASTUnit *TU);
|
||||
|
||||
|
|
Loading…
Reference in New Issue