SOURCE ../Basic/Attr.td
TARGET ClangAttrDump)
+clang_tablegen(AttrVisitor.inc -gen-clang-attr-ast-visitor
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE ../Basic/Attr.td
+ TARGET ClangAttrVisitor)
+
clang_tablegen(StmtNodes.inc -gen-clang-stmt-nodes
SOURCE ../Basic/StmtNodes.td
TARGET ClangStmtNodes)
CLANG_LEVEL := ../../..
TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
-BUILT_SOURCES = Attrs.inc AttrImpl.inc AttrDump.inc \
+BUILT_SOURCES = Attrs.inc AttrImpl.inc AttrDump.inc AttrVisitor.inc \
StmtNodes.inc DeclNodes.inc \
CommentNodes.inc CommentHTMLTags.inc \
CommentHTMLTagsProperties.inc \
$(Verb) $(ClangTableGen) -gen-clang-attr-dump -o $(call SYSPATH, $@) \
-I $(PROJ_SRC_DIR)/../../ $<
+$(ObjDir)/AttrVisitor.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
+ $(ObjDir)/.dir
+ $(Echo) "Building Clang attribute AST visitor with tblgen"
+ $(Verb) $(ClangTableGen) -gen-clang-attr-ast-visitor -o $(call SYSPATH, $@) \
+ -I $(PROJ_SRC_DIR)/../../ $<
+
$(ObjDir)/StmtNodes.inc.tmp : $(TD_SRC_DIR)/StmtNodes.td $(CLANG_TBLGEN) \
$(ObjDir)/.dir
$(Echo) "Building Clang statement node tables with tblgen"
#ifndef LLVM_CLANG_AST_RECURSIVEASTVISITOR_H
#define LLVM_CLANG_AST_RECURSIVEASTVISITOR_H
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
/// otherwise (including when the argument is a Null type location).
bool TraverseTypeLoc(TypeLoc TL);
+ /// \brief Recursively visit an attribute, by dispatching to
+ /// Traverse*Attr() based on the argument's dynamic type.
+ ///
+ /// \returns false if the visitation was terminated early, true
+ /// otherwise (including when the argument is a Null type location).
+ bool TraverseAttr(Attr *At);
+
/// \brief Recursively visit a declaration, by dispatching to
/// Traverse*Decl() based on the argument's dynamic type.
///
/// \returns false if the visitation was terminated early, true otherwise.
bool TraverseLambdaBody(LambdaExpr *LE);
+ // ---- Methods on Attrs ----
+
+ // \brief Visit an attribute.
+ bool VisitAttr(Attr *A) { return true; }
+
+ // Declare Traverse* and empty Visit* for all Attr classes.
+#define ATTR_VISITOR_DECLS_ONLY
+#include "clang/AST/AttrVisitor.inc"
+#undef ATTR_VISITOR_DECLS_ONLY
+
// ---- Methods on Stmts ----
// Declare Traverse*() for all concrete Stmt classes.
}
+// Define the Traverse*Attr(Attr* A) methods
+#include "clang/AST/AttrVisitor.inc"
+
+
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
if (!D)
switch (D->getKind()) {
#define ABSTRACT_DECL(DECL)
#define DECL(CLASS, BASE) \
- case Decl::CLASS: DISPATCH(CLASS##Decl, CLASS##Decl, D);
+ case Decl::CLASS: \
+ if (!getDerived().Traverse##CLASS##Decl(static_cast<CLASS##Decl*>(D))) \
+ return false; \
+ break;
#include "clang/AST/DeclNodes.inc"
- }
+ }
+ // Visit any attributes attached to this declaration.
+ for (Decl::attr_iterator I=D->attr_begin(), E=D->attr_end(); I != E; ++I) {
+ if (!getDerived().TraverseAttr(*I))
+ return false;
+ }
return true;
}
ClangAttrList
ClangAttrImpl
ClangAttrDump
+ ClangAttrVisitor
ClangCommentCommandInfo
ClangCommentCommandList
ClangCommentNodes
EXPECT_TRUE(Visitor.sawOnlyImplicitLambdaClasses());
}
+
+
+// Check to ensure that attributes and expressions within them are being
+// visited.
+class AttrVisitor : public ExpectedLocationVisitor<AttrVisitor> {
+public:
+ bool VisitMemberExpr(MemberExpr *ME) {
+ Match(ME->getMemberDecl()->getNameAsString(), ME->getLocStart());
+ return true;
+ }
+ bool VisitAttr(Attr *A) {
+ Match("Attr", A->getLocation());
+ return true;
+ }
+ bool VisitGuardedByAttr(GuardedByAttr *A) {
+ Match("guarded_by", A->getLocation());
+ return true;
+ }
+};
+
+
+TEST(RecursiveASTVisitor, AttributesAreVisited) {
+ AttrVisitor Visitor;
+ Visitor.ExpectMatch("Attr", 4, 24);
+ Visitor.ExpectMatch("guarded_by", 4, 24);
+ Visitor.ExpectMatch("mu1", 4, 35);
+ Visitor.ExpectMatch("Attr", 5, 29);
+ Visitor.ExpectMatch("mu1", 5, 54);
+ Visitor.ExpectMatch("mu2", 5, 59);
+ EXPECT_TRUE(Visitor.runOver(
+ "class Foo {\n"
+ " int mu1;\n"
+ " int mu2;\n"
+ " int a __attribute__((guarded_by(mu1)));\n"
+ " void bar() __attribute__((exclusive_locks_required(mu1, mu2)));\n"
+ "};\n"));
+}
+
+
} // end namespace clang
// These functions print the argument contents formatted in different ways.
virtual void writeAccessors(raw_ostream &OS) const = 0;
virtual void writeAccessorDefinitions(raw_ostream &OS) const {}
+ virtual void writeASTVisitorTraversal(raw_ostream &OS) const {}
virtual void writeCloneArgs(raw_ostream &OS) const = 0;
virtual void writeTemplateInstantiationArgs(raw_ostream &OS) const = 0;
virtual void writeTemplateInstantiation(raw_ostream &OS) const {}
: SimpleArgument(Arg, Attr, "Expr *")
{}
+ virtual void writeASTVisitorTraversal(raw_ostream &OS) const {
+ OS << " if (!"
+ << "getDerived().TraverseStmt(A->get" << getUpperName() << "()))\n";
+ OS << " return false;\n";
+ }
+
void writeTemplateInstantiationArgs(raw_ostream &OS) const {
OS << "tempInst" << getUpperName();
}
: VariadicArgument(Arg, Attr, "Expr *")
{}
+ virtual void writeASTVisitorTraversal(raw_ostream &OS) const {
+ OS << " {\n";
+ OS << " " << getType() << " *I = A->" << getLowerName()
+ << "_begin();\n";
+ OS << " " << getType() << " *E = A->" << getLowerName()
+ << "_end();\n";
+ OS << " for (; I != E; ++I) {\n";
+ OS << " if (!getDerived().TraverseStmt(*I))\n";
+ OS << " return false;\n";
+ OS << " }\n";
+ OS << " }\n";
+ }
+
void writeTemplateInstantiationArgs(raw_ostream &OS) const {
OS << "tempInst" << getUpperName() << ", "
<< "A->" << getLowerName() << "_size()";
OS << " return 0;\n";
}
+// Emits code used by RecursiveASTVisitor to visit attributes
+void EmitClangAttrASTVisitor(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Used by RecursiveASTVisitor to visit attributes.", OS);
+
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+ // Write method declarations for Traverse* methods.
+ // We emit this here because we only generate methods for attributes that
+ // are declared as ASTNodes.
+ OS << "#ifdef ATTR_VISITOR_DECLS_ONLY\n\n";
+ for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
+ Record &R = **I;
+ if (!R.getValueAsBit("ASTNode"))
+ continue;
+ OS << " bool Traverse"
+ << R.getName() << "Attr(" << R.getName() << "Attr *A);\n";
+ OS << " bool Visit"
+ << R.getName() << "Attr(" << R.getName() << "Attr *A) {\n"
+ << " return true; \n"
+ << " };\n";
+ }
+ OS << "\n#else // ATTR_VISITOR_DECLS_ONLY\n\n";
+
+ // Write individual Traverse* methods for each attribute class.
+ for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
+ Record &R = **I;
+ if (!R.getValueAsBit("ASTNode"))
+ continue;
+
+ OS << "template <typename Derived>\n"
+ << "bool RecursiveASTVisitor<Derived>::Traverse"
+ << R.getName() << "Attr(" << R.getName() << "Attr *A) {\n"
+ << " if (!getDerived().VisitAttr(A))\n"
+ << " return false;\n"
+ << " if (!getDerived().Visit" << R.getName() << "Attr(A))\n"
+ << " return false;\n";
+
+ std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
+ for (std::vector<Record*>::iterator ri = ArgRecords.begin(),
+ re = ArgRecords.end();
+ ri != re; ++ri) {
+ Record &ArgRecord = **ri;
+ Argument *Arg = createArgument(ArgRecord, R.getName());
+ assert(Arg);
+ Arg->writeASTVisitorTraversal(OS);
+ }
+
+ OS << " return true;\n";
+ OS << "}\n\n";
+ }
+
+ // Write generic Traverse routine
+ OS << "template <typename Derived>\n"
+ << "bool RecursiveASTVisitor<Derived>::TraverseAttr(Attr *A) {\n"
+ << " if (!A)\n"
+ << " return true;\n"
+ << "\n"
+ << " switch (A->getKind()) {\n"
+ << " default:\n"
+ << " return true;\n";
+
+ for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
+ Record &R = **I;
+ if (!R.getValueAsBit("ASTNode"))
+ continue;
+
+ OS << " case attr::" << R.getName() << ":\n"
+ << " return getDerived().Traverse" << R.getName() << "Attr("
+ << "cast<" << R.getName() << "Attr>(A));\n";
+ }
+ OS << " }\n"; // end case
+ OS << "}\n"; // end function
+ OS << "#endif // ATTR_VISITOR_DECLS_ONLY\n";
+}
+
+
// Emits the LateParsed property for attributes.
void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("llvm::StringSwitch code to match late parsed "
GenClangAttrPCHWrite,
GenClangAttrSpellingList,
GenClangAttrSpellingListIndex,
+ GenClangAttrASTVisitor,
GenClangAttrLateParsedList,
GenClangAttrTemplateInstantiate,
GenClangAttrParsedAttrList,
clEnumValN(GenClangAttrSpellingListIndex,
"gen-clang-attr-spelling-index",
"Generate a clang attribute spelling index"),
+ clEnumValN(GenClangAttrASTVisitor,
+ "gen-clang-attr-ast-visitor",
+ "Generate a recursive AST visitor for clang attributes"),
clEnumValN(GenClangAttrLateParsedList,
"gen-clang-attr-late-parsed-list",
"Generate a clang attribute LateParsed list"),
case GenClangAttrSpellingListIndex:
EmitClangAttrSpellingListIndex(Records, OS);
break;
+ case GenClangAttrASTVisitor:
+ EmitClangAttrASTVisitor(Records, OS);
+ break;
case GenClangAttrLateParsedList:
EmitClangAttrLateParsedList(Records, OS);
break;
void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrSpellingList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrASTVisitor(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS);