summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeLesley Hutchins <delesley@google.com>2013-12-30 17:24:36 +0000
committerDeLesley Hutchins <delesley@google.com>2013-12-30 17:24:36 +0000
commit484c793a298f320d5e2c79e20a854be054199dff (patch)
tree4a3d4bebba636d741268f4fbadf7e659d6aedcfd
parent445938035707b9c4accb6234b8da706fd7861911 (diff)
downloadclang-484c793a298f320d5e2c79e20a854be054199dff.tar.gz
Update RecursiveASTVisitor so that it visits attributes. This is currently
important for thread safety attributes, which contain expressions that were not being visited, and were thus invisible to various tools. There are now Visit*Attr methods that can be overridden for every attribute. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@198224 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/CMakeLists.txt5
-rw-r--r--include/clang/AST/Makefile8
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h34
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTest.cpp39
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp99
-rw-r--r--utils/TableGen/TableGen.cpp7
-rw-r--r--utils/TableGen/TableGenBackends.h1
8 files changed, 191 insertions, 3 deletions
diff --git a/include/clang/AST/CMakeLists.txt b/include/clang/AST/CMakeLists.txt
index ba54fa2aa9..260734f220 100644
--- a/include/clang/AST/CMakeLists.txt
+++ b/include/clang/AST/CMakeLists.txt
@@ -13,6 +13,11 @@ clang_tablegen(AttrDump.inc -gen-clang-attr-dump
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)
diff --git a/include/clang/AST/Makefile b/include/clang/AST/Makefile
index ae84bcfd58..85e6449c50 100644
--- a/include/clang/AST/Makefile
+++ b/include/clang/AST/Makefile
@@ -1,6 +1,6 @@
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 \
@@ -30,6 +30,12 @@ $(ObjDir)/AttrDump.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
$(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"
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 58034e8dc4..aa15f9fc53 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -14,6 +14,7 @@
#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"
@@ -182,6 +183,13 @@ public:
/// 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.
///
@@ -254,6 +262,16 @@ public:
/// \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.
@@ -623,6 +641,10 @@ bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL) {
}
+// Define the Traverse*Attr(Attr* A) methods
+#include "clang/AST/AttrVisitor.inc"
+
+
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
if (!D)
@@ -636,10 +658,18 @@ bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *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;
}
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 461e8b3ac1..e0b3c33890 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -65,6 +65,7 @@ add_dependencies(clangAST
ClangAttrList
ClangAttrImpl
ClangAttrDump
+ ClangAttrVisitor
ClangCommentCommandInfo
ClangCommentCommandList
ClangCommentNodes
diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp
index 323476766e..cd5767bdfa 100644
--- a/unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -577,4 +577,43 @@ TEST(RecursiveASTVisitor, LambdaClosureTypesAreImplicit) {
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
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index ef753946da..be4ae62578 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -149,6 +149,7 @@ namespace {
// 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 {}
@@ -794,6 +795,12 @@ namespace {
: 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();
}
@@ -826,6 +833,19 @@ namespace {
: 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()";
@@ -1568,6 +1588,85 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) {
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 "
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index 0e45d81d1a..e0cd027e73 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -32,6 +32,7 @@ enum ActionType {
GenClangAttrPCHWrite,
GenClangAttrSpellingList,
GenClangAttrSpellingListIndex,
+ GenClangAttrASTVisitor,
GenClangAttrLateParsedList,
GenClangAttrTemplateInstantiate,
GenClangAttrParsedAttrList,
@@ -82,6 +83,9 @@ cl::opt<ActionType> Action(
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"),
@@ -171,6 +175,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangAttrSpellingListIndex:
EmitClangAttrSpellingListIndex(Records, OS);
break;
+ case GenClangAttrASTVisitor:
+ EmitClangAttrASTVisitor(Records, OS);
+ break;
case GenClangAttrLateParsedList:
EmitClangAttrLateParsedList(Records, OS);
break;
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index 8904287060..d9256d89b7 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -38,6 +38,7 @@ void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS);
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);