aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/CMakeLists.txt5
-rw-r--r--include/clang/AST/Makefile9
-rw-r--r--lib/AST/ASTDumper.cpp28
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--test/Misc/ast-dump-attr.cpp97
-rw-r--r--test/Tooling/clang-check-ast-dump.cpp3
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp135
-rw-r--r--utils/TableGen/TableGen.cpp6
-rw-r--r--utils/TableGen/TableGenBackends.h1
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);