Modify ASTLocation and apart from being a Decl or Stmt, allow it to also be:

-A NamedDecl reference
-A TypeLoc

llvm-svn: 83095
This commit is contained in:
Argyrios Kyrtzidis 2009-09-29 19:44:27 +00:00
parent 73360e1bbb
commit 4cbe85904c
8 changed files with 155 additions and 131 deletions

View File

@ -14,7 +14,8 @@
#ifndef LLVM_CLANG_INDEX_ASTLOCATION_H
#define LLVM_CLANG_INDEX_ASTLOCATION_H
#include <cassert>
#include "clang/AST/TypeLoc.h"
#include "llvm/ADT/PointerIntPair.h"
namespace llvm {
class raw_ostream;
@ -23,7 +24,7 @@ namespace llvm {
namespace clang {
class Decl;
class Stmt;
class SourceRange;
class NamedDecl;
namespace idx {
class TranslationUnit;
@ -37,26 +38,105 @@ namespace idx {
/// like the declaration context, ASTContext, etc.
///
class ASTLocation {
const Decl *D;
const Stmt *Stm;
public:
enum NodeKind {
N_Decl, N_NamedRef, N_Stmt, N_Type
};
struct NamedRef {
NamedDecl *ND;
SourceLocation Loc;
NamedRef() : ND(0) { }
NamedRef(NamedDecl *nd, SourceLocation loc) : ND(nd), Loc(loc) { }
};
private:
llvm::PointerIntPair<Decl *, 2, NodeKind> ParentDecl;
union {
Decl *D;
Stmt *Stm;
struct {
NamedDecl *ND;
unsigned RawLoc;
} NDRef;
struct {
void *TyPtr;
void *Data;
} Ty;
};
public:
ASTLocation() : D(0), Stm(0) {}
ASTLocation() { }
explicit ASTLocation(const Decl *d, const Stmt *stm = 0) : D(d), Stm(stm) {
assert((Stm == 0 || isImmediateParent(D, Stm)) &&
"The Decl is not the immediate parent of the Stmt.");
explicit ASTLocation(const Decl *d)
: ParentDecl(const_cast<Decl*>(d), N_Decl), D(const_cast<Decl*>(d)) { }
ASTLocation(const Decl *parentDecl, const Stmt *stm)
: ParentDecl(const_cast<Decl*>(parentDecl), N_Stmt),
Stm(const_cast<Stmt*>(stm)) {
if (!stm) ParentDecl.setPointer(0);
}
const Decl *getDecl() const { return D; }
const Stmt *getStmt() const { return Stm; }
Decl *getDecl() { return const_cast<Decl*>(D); }
Stmt *getStmt() { return const_cast<Stmt*>(Stm); }
ASTLocation(const Decl *parentDecl, NamedDecl *ndRef, SourceLocation loc)
: ParentDecl(const_cast<Decl*>(parentDecl), N_NamedRef) {
if (ndRef) {
NDRef.ND = ndRef;
NDRef.RawLoc = loc.getRawEncoding();
} else
ParentDecl.setPointer(0);
}
bool isValid() const { return D != 0; }
ASTLocation(const Decl *parentDecl, TypeLoc tyLoc)
: ParentDecl(const_cast<Decl*>(parentDecl), N_Type) {
if (tyLoc) {
Ty.TyPtr = tyLoc.getSourceType().getAsOpaquePtr();
Ty.Data = tyLoc.getOpaqueData();
} else
ParentDecl.setPointer(0);
}
bool isValid() const { return ParentDecl.getPointer() != 0; }
bool isInvalid() const { return !isValid(); }
bool isDecl() const { return isValid() && Stm == 0; }
bool isStmt() const { return isValid() && Stm != 0; }
NodeKind getKind() const {
assert(isValid());
return (NodeKind)ParentDecl.getInt();
}
Decl *getParentDecl() const { return ParentDecl.getPointer(); }
Decl *AsDecl() const {
assert(getKind() == N_Decl);
return D;
}
Stmt *AsStmt() const {
assert(getKind() == N_Stmt);
return Stm;
}
NamedRef AsNamedRef() const {
assert(getKind() == N_NamedRef);
return NamedRef(NDRef.ND, SourceLocation::getFromRawEncoding(NDRef.RawLoc));
}
TypeLoc AsTypeLoc() const {
assert(getKind() == N_Type);
return TypeLoc(QualType::getFromOpaquePtr(Ty.TyPtr), Ty.Data);
}
Decl *dyn_AsDecl() const { return getKind() == N_Decl ? D : 0; }
Stmt *dyn_AsStmt() const { return getKind() == N_Stmt ? Stm : 0; }
NamedRef dyn_AsNamedRef() const {
return getKind() == N_Type ? AsNamedRef() : NamedRef();
}
TypeLoc dyn_AsTypeLoc() const {
return getKind() == N_Type ? AsTypeLoc() : TypeLoc();
}
bool isDecl() const { return isValid() && getKind() == N_Decl; }
bool isStmt() const { return isValid() && getKind() == N_Stmt; }
bool isNamedRef() const { return isValid() && getKind() == N_NamedRef; }
bool isType() const { return isValid() && getKind() == N_Type; }
/// \brief Returns the declaration that this ASTLocation references.
///
@ -70,17 +150,6 @@ public:
SourceRange getSourceRange() const;
/// \brief Checks that D is the immediate Decl parent of Node.
static bool isImmediateParent(const Decl *D, const Stmt *Node);
static const Decl *FindImmediateParent(const Decl *D, const Stmt *Node);
friend bool operator==(const ASTLocation &L, const ASTLocation &R) {
return L.D == R.D && L.Stm == R.Stm;
}
friend bool operator!=(const ASTLocation &L, const ASTLocation &R) {
return !(L == R);
}
void print(llvm::raw_ostream &OS) const;
};

View File

@ -51,10 +51,7 @@ void CGBuilder::VisitCallExpr(CallExpr *CE) {
if (FunctionDecl *CalleeDecl = CE->getDirectCallee()) {
Entity Ent = Entity::get(CalleeDecl, G.getProgram());
CallGraphNode *CalleeNode = G.getOrInsertFunction(Ent);
const Decl *Parent = ASTLocation::FindImmediateParent(FD, CE);
CallerNode->addCallee(ASTLocation(Parent, CE), CalleeNode);
CallerNode->addCallee(ASTLocation(FD, CE), CalleeNode);
}
}

View File

@ -39,94 +39,40 @@ static Decl *getDeclFromExpr(Stmt *E) {
Decl *ASTLocation::getReferencedDecl() {
if (isInvalid())
return 0;
if (isDecl())
return getDecl();
assert(getStmt());
return getDeclFromExpr(getStmt());
}
static bool isContainedInStatement(const Stmt *Node, const Stmt *Parent) {
assert(Node && Parent && "Passed null Node or Parent");
if (Node == Parent)
return true;
for (Stmt::const_child_iterator
I = Parent->child_begin(), E = Parent->child_end(); I != E; ++I) {
if (*I)
if (isContainedInStatement(Node, *I))
return true;
switch (getKind()) {
default: assert(0 && "Invalid Kind");
case N_Type:
return 0;
case N_Decl:
return D;
case N_NamedRef:
return NDRef.ND;
case N_Stmt:
return getDeclFromExpr(Stm);
}
return false;
}
const Decl *ASTLocation::FindImmediateParent(const Decl *D, const Stmt *Node) {
assert(D && Node && "Passed null Decl or null Stmt");
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
const Expr *Init = VD->getInit();
if (Init == 0)
return 0;
return isContainedInStatement(Node, Init) ? D : 0;
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (!FD->isThisDeclarationADefinition())
return 0;
for (DeclContext::decl_iterator
I = FD->decls_begin(), E = FD->decls_end(); I != E; ++I) {
const Decl *Child = FindImmediateParent(*I, Node);
if (Child)
return Child;
}
assert(FD->getBody() && "If not definition we should have exited already");
return isContainedInStatement(Node, FD->getBody()) ? D : 0;
}
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (!MD->getBody())
return 0;
for (DeclContext::decl_iterator
I = MD->decls_begin(), E = MD->decls_end(); I != E; ++I) {
const Decl *Child = FindImmediateParent(*I, Node);
if (Child)
return Child;
}
assert(MD->getBody() && "If not definition we should have exited already");
return isContainedInStatement(Node, MD->getBody()) ? D : 0;
}
if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
for (DeclContext::decl_iterator
I = BD->decls_begin(), E = BD->decls_end(); I != E; ++I) {
const Decl *Child = FindImmediateParent(*I, Node);
if (Child)
return Child;
}
assert(BD->getBody() && "BlockDecl without body ?");
return isContainedInStatement(Node, BD->getBody()) ? D : 0;
}
return 0;
}
bool ASTLocation::isImmediateParent(const Decl *D, const Stmt *Node) {
assert(D && Node && "Passed null Decl or null Stmt");
return D == FindImmediateParent(D, Node);
}
SourceRange ASTLocation::getSourceRange() const {
if (isInvalid())
return SourceRange();
return isDecl() ? getDecl()->getSourceRange() : getStmt()->getSourceRange();
switch (getKind()) {
default: assert(0 && "Invalid Kind");
return SourceRange();
case N_Decl:
return D->getSourceRange();
case N_Stmt:
return Stm->getSourceRange();
case N_NamedRef:
return SourceRange(AsNamedRef().Loc, AsNamedRef().Loc);
case N_Type:
return AsTypeLoc().getSourceRange();
}
return SourceRange();
}
void ASTLocation::print(llvm::raw_ostream &OS) const {
@ -134,21 +80,36 @@ void ASTLocation::print(llvm::raw_ostream &OS) const {
OS << "<< Invalid ASTLocation >>\n";
return;
}
ASTContext &Ctx = getParentDecl()->getASTContext();
OS << "[Decl: " << getDecl()->getDeclKindName() << " ";
if (const NamedDecl *ND = dyn_cast<NamedDecl>(getDecl()))
OS << ND->getNameAsString();
switch (getKind()) {
case N_Decl:
OS << "[Decl: " << AsDecl()->getDeclKindName() << " ";
if (const NamedDecl *ND = dyn_cast<NamedDecl>(AsDecl()))
OS << ND->getNameAsString();
break;
if (getStmt()) {
ASTContext &Ctx = getDecl()->getASTContext();
OS << " | Stmt: " << getStmt()->getStmtClassName() << " ";
getStmt()->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
case N_Stmt:
OS << "[Stmt: " << AsStmt()->getStmtClassName() << " ";
AsStmt()->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
break;
case N_NamedRef:
OS << "[NamedRef: " << AsNamedRef().ND->getDeclKindName() << " ";
OS << AsNamedRef().ND->getNameAsString();
break;
case N_Type: {
QualType T = AsTypeLoc().getSourceType();
OS << "[Type: " << T->getTypeClassName() << " " << T.getAsString();
}
}
OS << "] <";
SourceRange Range = getSourceRange();
SourceManager &SourceMgr = getDecl()->getASTContext().getSourceManager();
SourceManager &SourceMgr = Ctx.getSourceManager();
Range.getBegin().print(OS, SourceMgr);
OS << ", ";
Range.getEnd().print(OS, SourceMgr);

View File

@ -144,16 +144,15 @@ public:
/// It returns true "eagerly", meaning it will return false only if it can
/// "prove" statically that the interface cannot accept this message.
bool ValidReference(ASTLocation ASTLoc, ObjCInterfaceDecl *IFace) {
assert(ASTLoc.isValid());
assert(ASTLoc.isStmt());
// FIXME: Finding @selector references should be through another Analyzer
// method, like FindSelectors.
if (isa<ObjCSelectorExpr>(ASTLoc.getStmt()))
if (isa<ObjCSelectorExpr>(ASTLoc.AsStmt()))
return false;
ObjCInterfaceDecl *MsgD = 0;
ObjCMessageExpr *Msg = cast<ObjCMessageExpr>(ASTLoc.getStmt());
ObjCMessageExpr *Msg = cast<ObjCMessageExpr>(ASTLoc.AsStmt());
if (Msg->getReceiver()) {
const ObjCObjectPointerType *OPT =

View File

@ -183,7 +183,7 @@ ASTLocation DeclLocResolver::VisitDeclContext(DeclContext *DC) {
ASTLocation DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
ASTLocation ASTLoc = VisitDeclContext(TU);
if (ASTLoc.getDecl() == TU)
if (ASTLoc.getParentDecl() == TU)
return ASTLocation();
return ASTLoc;
}

View File

@ -26,13 +26,11 @@ struct S {
// RUN: index-test %t.ast -point-at %s:9:15 | grep for_var &&
// RUN: index-test %t.ast -point-at %s:9:43 > %t &&
// RUN: grep top_func_def %s &&
// RUN: grep '++for_var' %s &&
// RUN: grep '++for_var' %t &&
// RUN: index-test %t.ast -point-at %s:10:9 | grep local_var2 &&
// RUN: index-test %t.ast -point-at %s:10:30 > %t &&
// RUN: grep local_var2 %t &&
// RUN: grep 'for_var + 1' %t &&
// fields test.

View File

@ -512,8 +512,8 @@ CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name,
ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc);
Decl *Dcl = ALoc.getDecl();
Stmt *Stm = ALoc.getStmt();
Decl *Dcl = ALoc.getParentDecl();
Stmt *Stm = ALoc.dyn_AsStmt();
if (Dcl) {
if (Stm) {
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Stm)) {

View File

@ -132,7 +132,7 @@ static void ProcessObjCMessage(ObjCMessageExpr *Msg, Indexer &Idxer) {
Analyz.FindObjCMethods(Msg, Results);
for (ResultsTy::iterator
I = Results.begin(), E = Results.end(); I != E; ++I) {
const ObjCMethodDecl *D = cast<ObjCMethodDecl>(I->getDecl());
const ObjCMethodDecl *D = cast<ObjCMethodDecl>(I->AsDecl());
if (D->isThisDeclarationADefinition())
I->print(OS);
}
@ -146,7 +146,7 @@ static void ProcessASTLocation(ASTLocation ASTLoc, Indexer &Idxer) {
assert(ASTLoc.isValid());
if (ObjCMessageExpr *Msg =
dyn_cast_or_null<ObjCMessageExpr>(ASTLoc.getStmt()))
dyn_cast_or_null<ObjCMessageExpr>(ASTLoc.dyn_AsStmt()))
return ProcessObjCMessage(Msg, Idxer);
Decl *D = ASTLoc.getReferencedDecl();
@ -184,7 +184,7 @@ static void ProcessASTLocation(ASTLocation ASTLoc, Indexer &Idxer) {
Analyz.FindDeclarations(D, Results);
for (ResultsTy::iterator
I = Results.begin(), E = Results.end(); I != E; ++I) {
const Decl *D = I->getDecl();
const Decl *D = I->AsDecl();
bool isDef = false;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
isDef = FD->isThisDeclarationADefinition();
@ -285,7 +285,7 @@ int main(int argc, char **argv) {
llvm::raw_ostream &OS = llvm::outs();
ASTLoc.print(OS);
if (const char *Comment =
FirstAST->getASTContext().getCommentForDecl(ASTLoc.getDecl()))
FirstAST->getASTContext().getCommentForDecl(ASTLoc.dyn_AsDecl()))
OS << "Comment associated with this declaration:\n" << Comment << "\n";
} else {
ProcessASTLocation(ASTLoc, Idxer);