[AST] Add TableGen for StmtDataCollectors

Summary:
This adds an option "-gen-clang-data-collectors" to the Clang TableGen
that is used to generate StmtDataCollectors.inc.

Reviewers: arphaman, teemperor!

Subscribers: mgorny, cfe-commits

Differential Revision: https://reviews.llvm.org/D37383

llvm-svn: 312634
This commit is contained in:
Johannes Altmanninger 2017-09-06 13:20:51 +00:00
parent d614a1c15a
commit 1509da083a
9 changed files with 274 additions and 143 deletions

View File

@ -50,3 +50,6 @@ clang_tablegen(CommentCommandList.inc -gen-clang-comment-command-list
SOURCE CommentCommands.td
TARGET ClangCommentCommandList)
clang_tablegen(StmtDataCollectors.inc -gen-clang-data-collectors
SOURCE StmtDataCollectors.td
TARGET StmtDataCollectors)

View File

@ -0,0 +1,242 @@
class Stmt {
code Code = [{
addData(S->getStmtClass());
// This ensures that non-macro-generated code isn't identical to
// macro-generated code.
addData(data_collection::getMacroStack(S->getLocStart(), Context));
addData(data_collection::getMacroStack(S->getLocEnd(), Context));
}];
}
class Expr {
code Code = [{
addData(S->getType());
}];
}
//--- Builtin functionality ----------------------------------------------//
class ArrayTypeTraitExpr {
code Code = [{
addData(S->getTrait());
}];
}
class ExpressionTraitExpr {
code Code = [{
addData(S->getTrait());
}];
}
class PredefinedExpr {
code Code = [{
addData(S->getIdentType());
}];
}
class TypeTraitExpr {
code Code = [{
addData(S->getTrait());
for (unsigned i = 0; i < S->getNumArgs(); ++i)
addData(S->getArg(i)->getType());
}];
}
//--- Calls --------------------------------------------------------------//
class CallExpr {
code Code = [{
// Function pointers don't have a callee and we just skip hashing it.
if (const FunctionDecl *D = S->getDirectCallee()) {
// If the function is a template specialization, we also need to handle
// the template arguments as they are not included in the qualified name.
if (auto Args = D->getTemplateSpecializationArgs()) {
std::string ArgString;
// Print all template arguments into ArgString
llvm::raw_string_ostream OS(ArgString);
for (unsigned i = 0; i < Args->size(); ++i) {
Args->get(i).print(Context.getLangOpts(), OS);
// Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'.
OS << '\n';
}
OS.flush();
addData(ArgString);
}
addData(D->getQualifiedNameAsString());
}
}];
}
//--- Value references ---------------------------------------------------//
class DeclRefExpr {
code Code = [{
addData(S->getDecl()->getQualifiedNameAsString());
}];
}
class MemberExpr {
code Code = [{
addData(S->getMemberDecl()->getName());
}];
}
//--- Literals -----------------------------------------------------------//
class IntegerLiteral {
code Code = [{
addData(llvm::hash_value(S->getValue()));
}];
}
class FloatingLiteral {
code Code = [{
addData(llvm::hash_value(S->getValue()));
}];
}
class StringLiteral {
code Code = [{
addData(S->getString());
}];
}
class CXXBoolLiteralExpr {
code Code = [{
addData(S->getValue());
}];
}
class CharacterLiteral {
code Code = [{
addData(S->getValue());
}];
}
//--- Exceptions ---------------------------------------------------------//
class CXXCatchStmt {
code Code = [{
addData(S->getCaughtType());
}];
}
//--- C++ OOP Stmts ------------------------------------------------------//
class CXXDeleteExpr {
code Code = [{
addData(S->isArrayFormAsWritten()); addData(S->isGlobalDelete());
}];
}
//--- Casts --------------------------------------------------------------//
class ObjCBridgedCastExpr {
code Code = [{
addData(S->getBridgeKind());
}];
}
//--- Miscellaneous Exprs ------------------------------------------------//
class BinaryOperator {
code Code = [{
addData(S->getOpcode());
}];
}
class UnaryOperator {
code Code = [{
addData(S->getOpcode());
}];
}
//--- Control flow -------------------------------------------------------//
class GotoStmt {
code Code = [{
addData(S->getLabel()->getName());
}];
}
class IndirectGotoStmt {
code Code = [{
if (S->getConstantTarget())
addData(S->getConstantTarget()->getName());
}];
}
class LabelStmt {
code Code = [{
addData(S->getDecl()->getName());
}];
}
class MSDependentExistsStmt {
code Code = [{
addData(S->isIfExists());
}];
}
class AddrLabelExpr {
code Code = [{
addData(S->getLabel()->getName());
}];
}
//--- Objective-C --------------------------------------------------------//
class ObjCIndirectCopyRestoreExpr {
code Code = [{
addData(S->shouldCopy());
}];
}
class ObjCPropertyRefExpr {
code Code = [{
addData(S->isSuperReceiver()); addData(S->isImplicitProperty());
}];
}
class ObjCAtCatchStmt {
code Code = [{
addData(S->hasEllipsis());
}];
}
//--- Miscellaneous Stmts ------------------------------------------------//
class CXXFoldExpr {
code Code = [{
addData(S->isRightFold()); addData(S->getOperator());
}];
}
class GenericSelectionExpr {
code Code = [{
for (unsigned i = 0; i < S->getNumAssocs(); ++i) {
addData(S->getAssocType(i));
}
}];
}
class LambdaExpr {
code Code = [{
for (const LambdaCapture &C : S->captures()) {
addData(C.isPackExpansion());
addData(C.getCaptureKind());
if (C.capturesVariable())
addData(C.getCapturedVar()->getType());
}
addData(S->isGenericLambda());
addData(S->isMutable());
}];
}
class DeclStmt {
code Code = [{
auto numDecls = std::distance(S->decl_begin(), S->decl_end());
addData(static_cast<unsigned>(numDecls));
for (const Decl *D : S->decls()) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
addData(VD->getType());
}
}
}];
}
class AsmStmt {
code Code = [{
addData(S->isSimple());
addData(S->isVolatile());
addData(S->generateAsmString(Context));
for (unsigned i = 0; i < S->getNumInputs(); ++i) {
addData(S->getInputConstraint(i));
}
for (unsigned i = 0; i < S->getNumOutputs(); ++i) {
addData(S->getOutputConstraint(i));
}
for (unsigned i = 0; i < S->getNumClobbers(); ++i) {
addData(S->getClobber(i));
}
}];
}
class AttributedStmt {
code Code = [{
for (const Attr *A : S->getAttrs()) {
addData(std::string(A->getSpelling()));
}
}];
}

View File

@ -1,141 +0,0 @@
// The functions below collect the class specific data of each Stmt subclass.
DEF_ADD_DATA(Stmt, {
addData(S->getStmtClass());
// This ensures that non-macro-generated code isn't identical to
// macro-generated code.
addData(data_collection::getMacroStack(S->getLocStart(), Context));
addData(data_collection::getMacroStack(S->getLocEnd(), Context));
})
DEF_ADD_DATA(Expr, { addData(S->getType()); })
//--- Builtin functionality ----------------------------------------------//
DEF_ADD_DATA(ArrayTypeTraitExpr, { addData(S->getTrait()); })
DEF_ADD_DATA(ExpressionTraitExpr, { addData(S->getTrait()); })
DEF_ADD_DATA(PredefinedExpr, { addData(S->getIdentType()); })
DEF_ADD_DATA(TypeTraitExpr, {
addData(S->getTrait());
for (unsigned i = 0; i < S->getNumArgs(); ++i)
addData(S->getArg(i)->getType());
})
//--- Calls --------------------------------------------------------------//
DEF_ADD_DATA(CallExpr, {
// Function pointers don't have a callee and we just skip hashing it.
if (const FunctionDecl *D = S->getDirectCallee()) {
// If the function is a template specialization, we also need to handle
// the template arguments as they are not included in the qualified name.
if (auto Args = D->getTemplateSpecializationArgs()) {
std::string ArgString;
// Print all template arguments into ArgString
llvm::raw_string_ostream OS(ArgString);
for (unsigned i = 0; i < Args->size(); ++i) {
Args->get(i).print(Context.getLangOpts(), OS);
// Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'.
OS << '\n';
}
OS.flush();
addData(ArgString);
}
addData(D->getQualifiedNameAsString());
}
})
//--- Value references ---------------------------------------------------//
DEF_ADD_DATA(DeclRefExpr,
{ addData(S->getDecl()->getQualifiedNameAsString()); })
DEF_ADD_DATA(MemberExpr,
{ addData(S->getMemberDecl()->getName()); })
//--- Literals -----------------------------------------------------------//
DEF_ADD_DATA(IntegerLiteral, { addData(llvm::hash_value(S->getValue())); })
DEF_ADD_DATA(FloatingLiteral, { addData(llvm::hash_value(S->getValue())); })
DEF_ADD_DATA(StringLiteral, { addData(S->getString()); })
DEF_ADD_DATA(CXXBoolLiteralExpr, { addData(S->getValue()); })
DEF_ADD_DATA(CharacterLiteral, { addData(S->getValue()); })
//--- Exceptions ---------------------------------------------------------//
DEF_ADD_DATA(CXXCatchStmt, { addData(S->getCaughtType()); })
//--- C++ OOP Stmts ------------------------------------------------------//
DEF_ADD_DATA(CXXDeleteExpr, {
addData(S->isArrayFormAsWritten());
addData(S->isGlobalDelete());
})
//--- Casts --------------------------------------------------------------//
DEF_ADD_DATA(ObjCBridgedCastExpr, { addData(S->getBridgeKind()); })
//--- Miscellaneous Exprs ------------------------------------------------//
DEF_ADD_DATA(BinaryOperator, { addData(S->getOpcode()); })
DEF_ADD_DATA(UnaryOperator, { addData(S->getOpcode()); })
//--- Control flow -------------------------------------------------------//
DEF_ADD_DATA(GotoStmt, { addData(S->getLabel()->getName()); })
DEF_ADD_DATA(IndirectGotoStmt, {
if (S->getConstantTarget())
addData(S->getConstantTarget()->getName());
})
DEF_ADD_DATA(LabelStmt, { addData(S->getDecl()->getName()); })
DEF_ADD_DATA(MSDependentExistsStmt, { addData(S->isIfExists()); })
DEF_ADD_DATA(AddrLabelExpr, { addData(S->getLabel()->getName()); })
//--- Objective-C --------------------------------------------------------//
DEF_ADD_DATA(ObjCIndirectCopyRestoreExpr, { addData(S->shouldCopy()); })
DEF_ADD_DATA(ObjCPropertyRefExpr, {
addData(S->isSuperReceiver());
addData(S->isImplicitProperty());
})
DEF_ADD_DATA(ObjCAtCatchStmt, { addData(S->hasEllipsis()); })
//--- Miscellaneous Stmts ------------------------------------------------//
DEF_ADD_DATA(CXXFoldExpr, {
addData(S->isRightFold());
addData(S->getOperator());
})
DEF_ADD_DATA(GenericSelectionExpr, {
for (unsigned i = 0; i < S->getNumAssocs(); ++i) {
addData(S->getAssocType(i));
}
})
DEF_ADD_DATA(LambdaExpr, {
for (const LambdaCapture &C : S->captures()) {
addData(C.isPackExpansion());
addData(C.getCaptureKind());
if (C.capturesVariable())
addData(C.getCapturedVar()->getType());
}
addData(S->isGenericLambda());
addData(S->isMutable());
})
DEF_ADD_DATA(DeclStmt, {
auto numDecls = std::distance(S->decl_begin(), S->decl_end());
addData(static_cast<unsigned>(numDecls));
for (const Decl *D : S->decls()) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
addData(VD->getType());
}
}
})
DEF_ADD_DATA(AsmStmt, {
addData(S->isSimple());
addData(S->isVolatile());
addData(S->generateAsmString(Context));
for (unsigned i = 0; i < S->getNumInputs(); ++i) {
addData(S->getInputConstraint(i));
}
for (unsigned i = 0; i < S->getNumOutputs(); ++i) {
addData(S->getOutputConstraint(i));
}
for (unsigned i = 0; i < S->getNumClobbers(); ++i) {
addData(S->getClobber(i));
}
})
DEF_ADD_DATA(AttributedStmt, {
for (const Attr *A : S->getAttrs()) {
addData(std::string(A->getSpelling()));
}
})
#undef DEF_ADD_DATA

View File

@ -205,7 +205,7 @@ public:
ConstStmtVisitor<CloneTypeIIStmtDataCollector<T>>::Visit##CLASS(S); \
}
#include "../AST/StmtDataCollectors.inc"
#include "clang/AST/StmtDataCollectors.inc"
// Type II clones ignore variable names and literals, so let's skip them.
#define SKIP(CLASS) \

View File

@ -46,7 +46,7 @@ public:
ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \
}
#include "../../lib/AST/StmtDataCollectors.inc"
#include "clang/AST/StmtDataCollectors.inc"
};
} // end anonymous namespace

View File

@ -6,6 +6,7 @@ add_tablegen(clang-tblgen CLANG
ClangCommentCommandInfoEmitter.cpp
ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
ClangCommentHTMLTagsEmitter.cpp
ClangDataCollectorsEmitter.cpp
ClangDiagnosticsEmitter.cpp
ClangOptionDocEmitter.cpp
ClangSACheckersEmitter.cpp

View File

@ -0,0 +1,18 @@
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;
namespace clang {
void EmitClangDataCollectors(RecordKeeper &RK, raw_ostream &OS) {
const auto &Defs = RK.getClasses();
for (const auto &Entry : Defs) {
Record &R = *Entry.second;
OS << "DEF_ADD_DATA(" << R.getName() << ", {";
auto Code = R.getValue("Code")->getValue();
OS << Code->getAsUnquotedString() << "}\n)";
OS << "\n";
}
OS << "#undef DEF_ADD_DATA\n";
}
} // end namespace clang

View File

@ -57,6 +57,7 @@ enum ActionType {
GenAttrDocs,
GenDiagDocs,
GenOptDocs,
GenDataCollectors,
GenTestPragmaAttributeSupportedAttributes
};
@ -147,6 +148,8 @@ cl::opt<ActionType> Action(
clEnumValN(GenDiagDocs, "gen-diag-docs",
"Generate diagnostic documentation"),
clEnumValN(GenOptDocs, "gen-opt-docs", "Generate option documentation"),
clEnumValN(GenDataCollectors, "gen-clang-data-collectors",
"Generate data collectors for AST nodes"),
clEnumValN(GenTestPragmaAttributeSupportedAttributes,
"gen-clang-test-pragma-attribute-supported-attributes",
"Generate a list of attributes supported by #pragma clang "
@ -262,6 +265,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenOptDocs:
EmitClangOptDocs(Records, OS);
break;
case GenDataCollectors:
EmitClangDataCollectors(Records, OS);
break;
case GenTestPragmaAttributeSupportedAttributes:
EmitTestPragmaAttributeSupportedAttributes(Records, OS);
break;

View File

@ -75,6 +75,8 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS);
void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS);
void EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS);
void EmitClangDataCollectors(RecordKeeper &Records, raw_ostream &OS);
void EmitTestPragmaAttributeSupportedAttributes(RecordKeeper &Records,
raw_ostream &OS);