diff --git a/clang/include/clang/AST/ASTNode.h b/clang/include/clang/AST/ASTNode.h new file mode 100644 index 000000000000..852e94638057 --- /dev/null +++ b/clang/include/clang/AST/ASTNode.h @@ -0,0 +1,66 @@ +//===--- ASTNode.h - A pair ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ASTNode is Decl or a Stmt and its immediate Decl parent. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTNODE_H +#define LLVM_CLANG_AST_ASTNODE_H + +#include + +namespace llvm { + class raw_ostream; +} + +namespace clang { + class Decl; + class Stmt; + +/// \brief Represents a Decl or a Stmt and its immediate Decl parent. It's +/// immutable. +class ASTNode { + Decl *D; + Stmt *Stm; + +public: + ASTNode() : D(0), Stm(0) {} + + explicit ASTNode(const Decl *d, const Stmt *stm = 0) + : D(const_cast(d)), Stm(const_cast(stm)) { + assert((Stm == 0 || isImmediateParent(D, Stm)) && + "The Decl is not the immediate parent of the Stmt."); + } + + const Decl *getDecl() const { return D; } + const Stmt *getStmt() const { return Stm; } + Decl *getDecl() { return D; } + Stmt *getStmt() { return Stm; } + + bool isValid() const { return D != 0; } + bool isInvalid() const { return !isValid(); } + bool hasStmt() const { return Stm != 0; } + + /// \brief Checks that D is the immediate Decl parent of Node. + static bool isImmediateParent(Decl *D, Stmt *Node); + + friend bool operator==(const ASTNode &L, const ASTNode &R) { + return L.D == R.D && L.Stm == R.Stm; + } + friend bool operator!=(const ASTNode &L, const ASTNode &R) { + return !(L == R); + } + + void print(llvm::raw_ostream &OS); +}; + +} // namespace clang + +#endif diff --git a/clang/lib/AST/ASTNode.cpp b/clang/lib/AST/ASTNode.cpp new file mode 100644 index 000000000000..ff5ecc10de73 --- /dev/null +++ b/clang/lib/AST/ASTNode.cpp @@ -0,0 +1,90 @@ +//===--- ASTNode.h - A pair ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ASTNode is Decl or a Stmt and its immediate Decl parent. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTNode.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Expr.h" +using namespace clang; + +static bool isContainedInStatement(Stmt *Node, Stmt *Parent) { + assert(Node && Parent && "Passed null Node or Parent"); + + if (Node == Parent) + return true; + + for (Stmt::child_iterator + I = Parent->child_begin(), E = Parent->child_end(); I != E; ++I) { + if (isContainedInStatement(Node, *I)) + return true; + } + + return false; +} + +static Decl *FindImmediateParent(Decl *D, Stmt *Node) { + assert(D && Node && "Passed null Decl or null Stmt"); + + if (VarDecl *VD = dyn_cast(D)) { + Expr *Init = VD->getInit(); + if (Init == 0) + return 0; + return isContainedInStatement(Node, Init) ? D : 0; + } + + if (FunctionDecl *FD = dyn_cast(D)) { + if (!FD->isThisDeclarationADefinition()) + return 0; + + for (DeclContext::decl_iterator + I = FD->decls_begin(), E = FD->decls_end(); I != E; ++I) { + 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; + } + + return 0; +} + +bool ASTNode::isImmediateParent(Decl *D, Stmt *Node) { + assert(D && Node && "Passed null Decl or null Stmt"); + return D == FindImmediateParent(D, Node); +} + +void ASTNode::print(llvm::raw_ostream &OS) { + assert(isValid() && "ASTNode is not valid"); + + OS << "[Decl: " << getDecl()->getDeclKindName() << " "; + if (NamedDecl *ND = dyn_cast(getDecl())) + OS << ND->getNameAsString(); + + if (getStmt()) { + ASTContext &Ctx = getDecl()->getASTContext(); + OS << " | Stmt: " << getStmt()->getStmtClassName() << " "; + getStmt()->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions())); + } + + OS << "] <"; + + SourceRange Range = hasStmt() ? getStmt()->getSourceRange() + : getDecl()->getSourceRange(); + SourceManager &SourceMgr = getDecl()->getASTContext().getSourceManager(); + Range.getBegin().print(OS, SourceMgr); + OS << ", "; + Range.getEnd().print(OS, SourceMgr); + OS << ">\n"; +} diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt index ac4cbb2d296e..8fb86c6fc20b 100644 --- a/clang/lib/AST/CMakeLists.txt +++ b/clang/lib/AST/CMakeLists.txt @@ -4,6 +4,7 @@ add_clang_library(clangAST APValue.cpp ASTConsumer.cpp ASTContext.cpp + ASTNode.cpp CFG.cpp DeclarationName.cpp DeclBase.cpp