[libclang] Fix operations (token annotation, getting cursor, etc.) with a file region

inside an objc container that "contains" other file-level declarations.

When getting the array of file-level declarations that overlap with a file region,
we failed to report that the region overlaps with an objc container, if
the container had other file-level declarations declared lexically inside it.

Fix this by marking such declarations as "isTopLevelDeclInObjCContainer" in the AST
and handling them appropriately.

llvm-svn: 145109
This commit is contained in:
Argyrios Kyrtzidis 2011-11-23 20:27:36 +00:00
parent e4d082827d
commit 8ad3bab505
10 changed files with 96 additions and 4 deletions

View File

@ -244,6 +244,12 @@ private:
/// are regarded as "referenced" but not "used".
unsigned Referenced : 1;
/// \brief Whether this declaration is a top-level declaration (function,
/// global variable, etc.) that is lexically inside an objc container
/// definition.
/// FIXME: Consider setting the lexical context to the objc container.
unsigned TopLevelDeclInObjCContainer : 1;
protected:
/// Access - Used by C++ decls for the access specifier.
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
@ -282,7 +288,7 @@ protected:
: NextDeclInContext(0), DeclCtx(DC),
Loc(L), DeclKind(DK), InvalidDecl(0),
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
Access(AS_none), FromASTFile(0),
TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
ModulePrivate(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0)
@ -293,7 +299,7 @@ protected:
Decl(Kind DK, EmptyShell Empty)
: NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
Access(AS_none), FromASTFile(0),
TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
ModulePrivate(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0)
@ -452,6 +458,17 @@ public:
void setReferenced(bool R = true) { Referenced = R; }
/// \brief Whether this declaration is a top-level declaration (function,
/// global variable, etc.) that is lexically inside an objc container
/// definition.
bool isTopLevelDeclInObjCContainer() const {
return TopLevelDeclInObjCContainer;
}
void setTopLevelDeclInObjCContainer(bool V = true) {
TopLevelDeclInObjCContainer = V;
}
/// \brief Determine the availability of the given declaration.
///
/// This routine will determine the most restrictive availability of

View File

@ -2546,6 +2546,13 @@ void ASTUnit::findFileRegionDecls(FileID File, unsigned Offset, unsigned Length,
if (BeginIt != LocDecls.begin())
--BeginIt;
// If we are pointing at a top-level decl inside an objc container, we need
// to backtrack until we find it otherwise we will fail to report that the
// region overlaps with an objc container.
while (BeginIt != LocDecls.begin() &&
BeginIt->second->isTopLevelDeclInObjCContainer())
--BeginIt;
LocDeclsTy::iterator
EndIt = std::upper_bound(LocDecls.begin(), LocDecls.end(),
std::make_pair(Offset+Length, (Decl*)0),

View File

@ -3152,7 +3152,13 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
D.setFunctionDefinitionKind(FDK_Declaration);
return HandleDeclarator(S, D, MultiTemplateParamsArg(*this));
Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg(*this));
if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() &&
Dcl->getDeclContext()->isFileContext())
Dcl->setTopLevelDeclInObjCContainer();
return Dcl;
}
/// DiagnoseClassNameShadow - Implement C++ [class.mem]p13:
@ -4788,6 +4794,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
isVirtualOkay);
if (!NewFD) return 0;
if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer())
NewFD->setTopLevelDeclInObjCContainer();
if (getLangOptions().CPlusPlus) {
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();

View File

@ -2326,6 +2326,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
for (unsigned i = 0; i != tuvNum; i++) {
DeclGroupRef DG = allTUVars[i].getAsVal<DeclGroupRef>();
for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
(*I)->setTopLevelDeclInObjCContainer();
Consumer.HandleTopLevelDeclInObjCContainer(DG);
}
}

View File

@ -4293,6 +4293,14 @@ void ASTReader::FindFileRegionDecls(FileID File,
if (BeginIt != DInfo.Decls.begin())
--BeginIt;
// If we are pointing at a top-level decl inside an objc container, we need
// to backtrack until we find it otherwise we will fail to report that the
// region overlaps with an objc container.
while (BeginIt != DInfo.Decls.begin() &&
GetDecl(getGlobalDeclID(*DInfo.Mod, *BeginIt))
->isTopLevelDeclInObjCContainer())
--BeginIt;
ArrayRef<serialization::LocalDeclID>::iterator
EndIt = std::upper_bound(DInfo.Decls.begin(), DInfo.Decls.end(),
EndLoc, DIDComp);

View File

@ -249,6 +249,7 @@ void ASTDeclReader::VisitDecl(Decl *D) {
D->setImplicit(Record[Idx++]);
D->setUsed(Record[Idx++]);
D->setReferenced(Record[Idx++]);
D->TopLevelDeclInObjCContainer = Record[Idx++];
D->setAccess((AccessSpecifier)Record[Idx++]);
D->FromASTFile = true;
D->ModulePrivate = Record[Idx++];

View File

@ -154,6 +154,7 @@ void ASTDeclWriter::VisitDecl(Decl *D) {
Record.push_back(D->isImplicit());
Record.push_back(D->isUsed(false));
Record.push_back(D->isReferenced());
Record.push_back(D->TopLevelDeclInObjCContainer);
Record.push_back(D->getAccess());
Record.push_back(D->ModulePrivate);
}
@ -1278,6 +1279,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
@ -1308,6 +1310,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
@ -1343,6 +1346,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
@ -1388,6 +1392,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
@ -1427,6 +1432,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
@ -1473,6 +1479,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
@ -1499,6 +1506,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl

View File

@ -0,0 +1,33 @@
@interface Foo
void func1(int);
void func2(int);
-(void)meth1;
-(void)meth2;
@end
@implementation Foo
void func(int);
static int glob1;
static int glob2;
-(void)meth1 {}
-(void)meth2 {}
@end
// RUN: c-index-test -write-pch %t.h.pch -x objective-c-header %s.h
// RUN: c-index-test -test-annotate-tokens=%s:5:1:7:1 %s -include %t.h \
// RUN: | FileCheck -check-prefix=INTER %s
// CHECK-INTER: Identifier: "meth1" [5:8 - 5:13] ObjCInstanceMethodDecl=meth1:5:1
// CHECK-INTER: Identifier: "meth2" [6:8 - 6:13] ObjCInstanceMethodDecl=meth2:6:1
// RUN: c-index-test -test-annotate-tokens=%s:14:1:16:1 %s -include %t.h \
// RUN: | FileCheck -check-prefix=IMPL %s
// CHECK-IMPL: Identifier: "meth1" [14:8 - 14:13] ObjCInstanceMethodDecl=meth1:14:1 (Definition)
// CHECK-IMPL: Identifier: "meth2" [15:8 - 15:13] ObjCInstanceMethodDecl=meth2:15:1 (Definition)
// RUN: c-index-test -test-annotate-tokens=%s.h:5:1:7:1 %s -include %t.h \
// RUN: | FileCheck -check-prefix=PCH %s
// CHECK-PCH: Identifier: "meth1" [5:8 - 5:13] ObjCInstanceMethodDecl=meth1:5:1
// CHECK-PCH: Identifier: "meth2" [6:8 - 6:13] ObjCInstanceMethodDecl=meth2:6:1

View File

@ -0,0 +1,7 @@
@interface FooPCH
void funcPCH1(int);
void funcPCH2(int);
-(void)meth1;
-(void)meth2;
@end

View File

@ -260,7 +260,7 @@ void CursorVisitor::visitDeclsFromFileRegion(FileID File,
// If we didn't find any file level decls for the file, try looking at the
// file that it was included from.
while (Decls.empty()) {
while (Decls.empty() || Decls.front()->isTopLevelDeclInObjCContainer()) {
bool Invalid = false;
const SrcMgr::SLocEntry &SLEntry = SM.getSLocEntry(File, &Invalid);
if (Invalid)