diff options
author | Alexander Kornienko <alexfh@google.com> | 2013-01-07 17:53:08 +0000 |
---|---|---|
committer | Alexander Kornienko <alexfh@google.com> | 2013-01-07 17:53:08 +0000 |
commit | c3cd2b0d538e4db78f1bcbedd0085e2005ce5c51 (patch) | |
tree | 0529c5ef39bb2b560eefbda8a2b45a340eee87b1 | |
parent | 07fc1ba7553f2f5bf26984091197311decd9028e (diff) |
Implement Attr dumping for -ast-dump.
http://llvm-reviews.chandlerc.com/D234
Patch by Philip Craig!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@171760 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/CMakeLists.txt | 5 | ||||
-rw-r--r-- | include/clang/AST/Makefile | 9 | ||||
-rw-r--r-- | lib/AST/ASTDumper.cpp | 28 | ||||
-rw-r--r-- | lib/AST/CMakeLists.txt | 1 | ||||
-rw-r--r-- | test/Misc/ast-dump-attr.cpp | 97 | ||||
-rw-r--r-- | test/Tooling/clang-check-ast-dump.cpp | 3 | ||||
-rw-r--r-- | utils/TableGen/ClangAttrEmitter.cpp | 135 | ||||
-rw-r--r-- | utils/TableGen/TableGen.cpp | 6 | ||||
-rw-r--r-- | utils/TableGen/TableGenBackends.h | 1 |
9 files changed, 270 insertions, 15 deletions
diff --git a/include/clang/AST/CMakeLists.txt b/include/clang/AST/CMakeLists.txt index 4c4c0fb0a0..547124c95e 100644 --- a/include/clang/AST/CMakeLists.txt +++ b/include/clang/AST/CMakeLists.txt @@ -8,6 +8,11 @@ clang_tablegen(AttrImpl.inc -gen-clang-attr-impl SOURCE ../Basic/Attr.td TARGET ClangAttrImpl) +clang_tablegen(AttrDump.inc -gen-clang-attr-dump + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE ../Basic/Attr.td + TARGET ClangAttrDump) + 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 7fb33f2774..61a0b64ce9 100644 --- a/include/clang/AST/Makefile +++ b/include/clang/AST/Makefile @@ -1,6 +1,7 @@ CLANG_LEVEL := ../../.. TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic -BUILT_SOURCES = Attrs.inc AttrImpl.inc StmtNodes.inc DeclNodes.inc \ +BUILT_SOURCES = Attrs.inc AttrImpl.inc AttrDump.inc \ + StmtNodes.inc DeclNodes.inc \ CommentNodes.inc CommentHTMLTags.inc \ CommentHTMLTagsProperties.inc CommentCommandInfo.inc @@ -20,6 +21,12 @@ $(ObjDir)/AttrImpl.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \ $(Verb) $(ClangTableGen) -gen-clang-attr-impl -o $(call SYSPATH, $@) \ -I $(PROJ_SRC_DIR)/../../ $< +$(ObjDir)/AttrDump.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \ + $(ObjDir)/.dir + $(Echo) "Building Clang attribute dumper with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-attr-dump -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/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index d52b089462..c0180033ed 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclVisitor.h" @@ -74,6 +75,7 @@ namespace { void dumpDeclRef(const Decl *Node, const char *Label = 0); void dumpName(const NamedDecl *D); void dumpDeclContext(const DeclContext *DC); + void dumpAttr(const Attr *A); // C++ Utilities void dumpAccessSpecifier(AccessSpecifier AS); @@ -141,6 +143,7 @@ namespace { // Stmts. void VisitStmt(Stmt *Node); void VisitDeclStmt(DeclStmt *Node); + void VisitAttributedStmt(AttributedStmt *Node); void VisitLabelStmt(LabelStmt *Node); void VisitGotoStmt(GotoStmt *Node); @@ -308,6 +311,19 @@ void ASTDumper::dumpDeclContext(const DeclContext *DC) { dumpDecl(*I); } +void ASTDumper::dumpAttr(const Attr *A) { + IndentScope Indent(*this); + switch (A->getKind()) { +#define ATTR(X) case attr::X: OS << #X; break; +#include "clang/Basic/AttrList.inc" + default: llvm_unreachable("unexpected attribute kind"); + } + OS << "Attr"; + dumpPointer(A); + dumpSourceRange(A->getRange()); +#include "clang/AST/AttrDump.inc" +} + //===----------------------------------------------------------------------===// // C++ Utilities //===----------------------------------------------------------------------===// @@ -425,6 +441,11 @@ void ASTDumper::dumpDecl(Decl *D) { dumpPointer(D); dumpSourceRange(D->getSourceRange()); DeclVisitor<ASTDumper>::Visit(D); + if (D->hasAttrs()) { + for (AttrVec::const_iterator I = D->getAttrs().begin(), + E = D->getAttrs().end(); I != E; ++I) + dumpAttr(*I); + } // Decls within functions are visited by the body if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D)) dumpDeclContext(dyn_cast<DeclContext>(D)); @@ -959,6 +980,13 @@ void ASTDumper::VisitDeclStmt(DeclStmt *Node) { dumpDecl(*I); } +void ASTDumper::VisitAttributedStmt(AttributedStmt *Node) { + VisitStmt(Node); + for (ArrayRef<const Attr*>::iterator I = Node->getAttrs().begin(), + E = Node->getAttrs().end(); I != E; ++I) + dumpAttr(*I); +} + void ASTDumper::VisitLabelStmt(LabelStmt *Node) { VisitStmt(Node); OS << " '" << Node->getName() << "'"; diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 1bc252322d..f5e6c9605f 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -64,6 +64,7 @@ add_dependencies(clangAST ClangAttrClasses ClangAttrList ClangAttrImpl + ClangAttrDump ClangCommentCommandInfo ClangCommentNodes ClangCommentHTMLTags diff --git a/test/Misc/ast-dump-attr.cpp b/test/Misc/ast-dump-attr.cpp new file mode 100644 index 0000000000..57d52b1ce5 --- /dev/null +++ b/test/Misc/ast-dump-attr.cpp @@ -0,0 +1,97 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s + +int TestLocation +__attribute__((unused)); +// CHECK: VarDecl{{.*}}TestLocation +// CHECK-NEXT: UnusedAttr 0x{{[^ ]*}} <line:[[@LINE-2]]:16> + +int TestIndent +__attribute__((unused)); +// CHECK: {{^\(VarDecl.*TestIndent[^()]*$}} +// CHECK-NEXT: {{^ \(UnusedAttr[^()]*\)\)$}} + +void TestAttributedStmt() { + switch (1) { + case 1: + [[clang::fallthrough]]; + case 2: + ; + } +} +// CHECK: FunctionDecl{{.*}}TestAttributedStmt +// CHECK: AttributedStmt +// CHECK-NEXT: FallThroughAttr +// CHECK-NEXT: NullStmt + +[[clang::warn_unused_result]] int TestCXX11DeclAttr(); +// CHECK: FunctionDecl{{.*}}TestCXX11DeclAttr +// CHECK-NEXT: WarnUnusedResultAttr + +int TestAlignedNull __attribute__((aligned)); +// CHECK: VarDecl{{.*}}TestAlignedNull +// CHECK-NEXT: AlignedAttr +// CHECK-NEXT: <<<NULL>>> + +int TestAlignedExpr __attribute__((aligned(4))); +// CHECK: VarDecl{{.*}}TestAlignedExpr +// CHECK-NEXT: AlignedAttr +// CHECK-NEXT: IntegerLiteral + +int TestEnum __attribute__((visibility("default"))); +// CHECK: VarDecl{{.*}}TestEnum +// CHECK-NEXT: VisibilityAttr{{.*}} Default + +class __attribute__((lockable)) Mutex { +} mu1, mu2; +int TestExpr __attribute__((guarded_by(mu1))); +// CHECK: VarDecl{{.*}}TestExpr +// CHECK-NEXT: GuardedByAttr +// CHECK-NEXT: DeclRefExpr{{.*}}mu1 + +class Mutex TestVariadicExpr __attribute__((acquired_after(mu1, mu2))); +// CHECK: VarDecl{{.*}}TestVariadicExpr +// CHECK: AcquiredAfterAttr +// CHECK-NEXT: DeclRefExpr{{.*}}mu1 +// CHECK-NEXT: DeclRefExpr{{.*}}mu2 + +void function1(void *) { + int TestFunction __attribute__((cleanup(function1))); +} +// CHECK: VarDecl{{.*}}TestFunction +// CHECK-NEXT: CleanupAttr{{.*}} Function{{.*}}function1 + +void TestIdentifier(void *, int) +__attribute__((pointer_with_type_tag(ident1,1,2))); +// CHECK: FunctionDecl{{.*}}TestIdentifier +// CHECK: ArgumentWithTypeTagAttr{{.*}} ident1 + +void TestBool(void *, int) +__attribute__((pointer_with_type_tag(bool1,1,2))); +// CHECK: FunctionDecl{{.*}}TestBool +// CHECK: ArgumentWithTypeTagAttr{{.*}} IsPointer + +void TestUnsigned(void *, int) +__attribute__((pointer_with_type_tag(unsigned1,1,2))); +// CHECK: FunctionDecl{{.*}}TestUnsigned +// CHECK: ArgumentWithTypeTagAttr{{.*}} 0 1 + +void TestInt(void) __attribute__((constructor(123))); +// CHECK: FunctionDecl{{.*}}TestInt +// CHECK-NEXT: ConstructorAttr{{.*}} 123 + +int TestString __attribute__((alias("alias1"))); +// CHECK: VarDecl{{.*}}TestString +// CHECK-NEXT: AliasAttr{{.*}} "alias1" + +extern struct s1 TestType +__attribute__((type_tag_for_datatype(ident1,int))); +// CHECK: VarDecl{{.*}}TestType +// CHECK-NEXT: TypeTagForDatatypeAttr{{.*}} int + +void *TestVariadicUnsigned1(int) __attribute__((alloc_size(1))); +// CHECK: FunctionDecl{{.*}}TestVariadicUnsigned1 +// CHECK: AllocSizeAttr{{.*}} 0 + +void *TestVariadicUnsigned2(int, int) __attribute__((alloc_size(1,2))); +// CHECK: FunctionDecl{{.*}}TestVariadicUnsigned2 +// CHECK: AllocSizeAttr{{.*}} 0 1 diff --git a/test/Tooling/clang-check-ast-dump.cpp b/test/Tooling/clang-check-ast-dump.cpp index 90827e10b7..7425b7f875 100644 --- a/test/Tooling/clang-check-ast-dump.cpp +++ b/test/Tooling/clang-check-ast-dump.cpp @@ -31,7 +31,8 @@ // RUN: clang-check -ast-dump -ast-dump-filter test_namespace::TheClass::n "%s" -- 2>&1 | FileCheck -check-prefix CHECK-ATTR %s // CHECK-ATTR: test_namespace // CHECK-ATTR-NEXT: (FieldDecl{{.*}}n -// FIXME: attribute dumping not implemented yet +// CHECK-ATTR-NEXT: (AlignedAttr +// CHECK-ATTR-NEXT: (BinaryOperator // // RUN: clang-check -ast-dump -ast-dump-filter test_namespace::AfterNullNode "%s" -- 2>&1 | FileCheck -check-prefix CHECK-AFTER-NULL %s // CHECK-AFTER-NULL: class AfterNullNode diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index 08f4499aeb..3651636e95 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -125,6 +125,8 @@ namespace { virtual void writePCHReadDecls(raw_ostream &OS) const = 0; virtual void writePCHWrite(raw_ostream &OS) const = 0; virtual void writeValue(raw_ostream &OS) const = 0; + virtual void writeDump(raw_ostream &OS) const = 0; + virtual void writeDumpChildren(raw_ostream &OS) const {} }; class SimpleArgument : public Argument { @@ -181,6 +183,28 @@ namespace { OS << "\" << get" << getUpperName() << "() << \""; } } + void writeDump(raw_ostream &OS) const { + if (type == "FunctionDecl *") { + OS << " OS << \" \";\n"; + OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n"; + } else if (type == "IdentifierInfo *") { + OS << " OS << \" \" << SA->get" << getUpperName() + << "()->getName();\n"; + } else if (type == "QualType") { + OS << " OS << \" \" << SA->get" << getUpperName() + << "().getAsString();\n"; + } else if (type == "SourceLocation") { + OS << " OS << \" \";\n"; + OS << " SA->get" << getUpperName() << "().print(OS, *SM);\n"; + } else if (type == "bool") { + OS << " if (SA->get" << getUpperName() << "()) OS << \" " + << getUpperName() << "\";\n"; + } else if (type == "int" || type == "unsigned") { + OS << " OS << \" \" << SA->get" << getUpperName() << "();\n"; + } else { + llvm_unreachable("Unknown SimpleArgument type!"); + } + } }; class StringArgument : public Argument { @@ -241,6 +265,10 @@ namespace { void writeValue(raw_ostream &OS) const { OS << "\\\"\" << get" << getUpperName() << "() << \"\\\""; } + void writeDump(raw_ostream &OS) const { + OS << " OS << \" \\\"\" << SA->get" << getUpperName() + << "() << \"\\\"\";\n"; + } }; class AlignedArgument : public Argument { @@ -353,6 +381,15 @@ namespace { << " " << getLowerName() << "Expr->printPretty(OS, 0, Policy);\n" << " OS << \""; } + void writeDump(raw_ostream &OS) const { + } + void writeDumpChildren(raw_ostream &OS) const { + OS << " if (SA->is" << getUpperName() << "Expr())\n"; + OS << " dumpStmt(SA->get" << getUpperName() << "Expr());\n"; + OS << " else\n"; + OS << " dumpType(SA->get" << getUpperName() + << "Type()->getType());\n"; + } }; class VariadicArgument : public Argument { @@ -439,17 +476,30 @@ namespace { << " }\n"; OS << " OS << \""; } + void writeDump(raw_ostream &OS) const { + OS << " for (" << getAttrName() << "Attr::" << getLowerName() + << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" + << getLowerName() << "_end(); I != E; ++I)\n"; + OS << " OS << \" \" << *I;\n"; + } }; class EnumArgument : public Argument { std::string type; - std::vector<StringRef> values, enums; + std::vector<StringRef> values, enums, uniques; public: EnumArgument(Record &Arg, StringRef Attr) : Argument(Arg, Attr), type(Arg.getValueAsString("Type")), values(getValueAsListOfStrings(Arg, "Values")), - enums(getValueAsListOfStrings(Arg, "Enums")) - {} + enums(getValueAsListOfStrings(Arg, "Enums")), + uniques(enums) + { + // Calculate the various enum values + std::sort(uniques.begin(), uniques.end()); + uniques.erase(std::unique(uniques.begin(), uniques.end()), uniques.end()); + // FIXME: Emit a proper error + assert(!uniques.empty()); + } void writeAccessors(raw_ostream &OS) const { OS << " " << type << " get" << getUpperName() << "() const {\n"; @@ -469,16 +519,8 @@ namespace { OS << type << " " << getUpperName(); } void writeDeclarations(raw_ostream &OS) const { - // Calculate the various enum values - std::vector<StringRef> uniques(enums); - std::sort(uniques.begin(), uniques.end()); - uniques.erase(std::unique(uniques.begin(), uniques.end()), - uniques.end()); - // FIXME: Emit a proper error - assert(!uniques.empty()); - - std::vector<StringRef>::iterator i = uniques.begin(), - e = uniques.end(); + std::vector<StringRef>::const_iterator i = uniques.begin(), + e = uniques.end(); // The last one needs to not have a comma. --e; @@ -505,6 +547,21 @@ namespace { void writeValue(raw_ostream &OS) const { OS << "\" << get" << getUpperName() << "() << \""; } + void writeDump(raw_ostream &OS) const { + OS << " switch(SA->get" << getUpperName() << "()) {\n"; + OS << " default:\n"; + OS << " llvm_unreachable(\"Unknown " << getAttrName() << "Attr::" + << type << "!\");\n"; + OS << " break;\n"; + + for (std::vector<StringRef>::const_iterator I = uniques.begin(), + E = uniques.end(); I != E; ++I) { + OS << " case " << getAttrName() << "Attr::" << *I << ":\n"; + OS << " OS << \" " << *I << "\";\n"; + OS << " break;\n"; + } + OS << " }\n"; + } }; class VersionArgument : public Argument { @@ -552,6 +609,9 @@ namespace { void writeValue(raw_ostream &OS) const { OS << getLowerName() << "=\" << get" << getUpperName() << "() << \""; } + void writeDump(raw_ostream &OS) const { + OS << " OS << \" \" << SA->get" << getUpperName() << "();\n"; + } }; class ExprArgument : public SimpleArgument { @@ -575,6 +635,13 @@ namespace { << "Result.takeAs<Expr>();\n"; OS << " }\n"; } + + void writeDump(raw_ostream &OS) const { + } + + void writeDumpChildren(raw_ostream &OS) const { + OS << " dumpStmt(SA->get" << getUpperName() << "());\n"; + } }; class VariadicExprArgument : public VariadicArgument { @@ -607,6 +674,16 @@ namespace { OS << " }\n"; OS << " }\n"; } + + void writeDump(raw_ostream &OS) const { + } + + void writeDumpChildren(raw_ostream &OS) const { + OS << " for (" << getAttrName() << "Attr::" << getLowerName() + << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" + << getLowerName() << "_end(); I != E; ++I)\n"; + OS << " dumpStmt(*I);\n"; + } }; } @@ -1163,4 +1240,36 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { << "}\n"; } +// Emits the code to dump an attribute. +void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS) { + OS << + " switch (A->getKind()) {\n" + " default:\n" + " llvm_unreachable(\"Unknown attribute kind!\");\n" + " break;\n"; + std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args; + 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"; + Args = R.getValueAsListOfDefs("Args"); + if (!Args.empty()) { + OS << " const " << R.getName() << "Attr *SA = cast<" << R.getName() + << "Attr>(A);\n"; + for (std::vector<Record*>::iterator I = Args.begin(), E = Args.end(); + I != E; ++I) + createArgument(**I, R.getName())->writeDump(OS); + for (std::vector<Record*>::iterator I = Args.begin(), E = Args.end(); + I != E; ++I) + createArgument(**I, R.getName())->writeDumpChildren(OS); + } + OS << + " break;\n" + " }\n"; + } + OS << " }\n"; +} + } // end namespace clang diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index 32aaf71015..7e9076f7b3 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -33,6 +33,7 @@ enum ActionType { GenClangAttrTemplateInstantiate, GenClangAttrParsedAttrList, GenClangAttrParsedAttrKinds, + GenClangAttrDump, GenClangDiagsDefs, GenClangDiagGroups, GenClangDiagsIndexName, @@ -81,6 +82,8 @@ namespace { clEnumValN(GenClangAttrParsedAttrKinds, "gen-clang-attr-parsed-attr-kinds", "Generate a clang parsed attribute kinds"), + clEnumValN(GenClangAttrDump, "gen-clang-attr-dump", + "Generate clang attribute dumper"), clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs", "Generate Clang diagnostics definitions"), clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups", @@ -153,6 +156,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenClangAttrParsedAttrKinds: EmitClangAttrParsedAttrKinds(Records, OS); break; + case GenClangAttrDump: + EmitClangAttrDump(Records, OS); + break; case GenClangDiagsDefs: EmitClangDiagsDefs(Records, OS, ClangComponent); break; diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h index 838fc84dca..54e76fdd5e 100644 --- a/utils/TableGen/TableGenBackends.h +++ b/utils/TableGen/TableGenBackends.h @@ -39,6 +39,7 @@ void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS); void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, const std::string &Component); |