Add support for pretty-printing attributes, from Richard Membarth!

llvm-svn: 145002
This commit is contained in:
Douglas Gregor 2011-11-19 19:22:57 +00:00
parent 9f39a765e2
commit 49ccfaa938
3 changed files with 87 additions and 6 deletions

View File

@ -23,6 +23,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstring>
#include <algorithm>
@ -103,6 +104,9 @@ public:
// Clone this attribute.
virtual Attr* clone(ASTContext &C) const = 0;
// Pretty print this attribute.
virtual void printPretty(llvm::raw_ostream &OS, ASTContext &C) const = 0;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *) { return true; }
};

View File

@ -85,6 +85,7 @@ namespace {
void PrintTemplateParameters(const TemplateParameterList *Params,
const TemplateArgumentList *Args);
void prettyPrintAttributes(Decl *D);
};
}
@ -182,6 +183,16 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
return Out;
}
void DeclPrinter::prettyPrintAttributes(Decl *D) {
if (D->hasAttrs()) {
AttrVec &Attrs = D->getAttrs();
for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; ++i) {
Attr *A = *i;
A->printPretty(Out, Context);
}
}
}
void DeclPrinter::ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls) {
this->Indent();
Decl::printGroup(Decls.data(), Decls.size(), Out, Policy, Indentation);
@ -320,6 +331,7 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
Out << "__module_private__ ";
}
Out << S;
prettyPrintAttributes(D);
}
void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) {
@ -350,6 +362,7 @@ void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
VisitDeclContext(D);
Indent() << "}";
}
prettyPrintAttributes(D);
}
void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
@ -466,12 +479,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
}
if (D->hasAttr<NoReturnAttr>())
Proto += " __attribute((noreturn))";
if (D->hasAttr<ReturnsTwiceAttr>())
Proto += " __attribute((returns_twice))";
if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
bool HasInitializerList = false;
for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
@ -542,6 +549,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
Out << Proto;
prettyPrintAttributes(D);
if (D->isPure())
Out << " = 0";
@ -588,6 +596,7 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
Out << " = ";
Init->printPretty(Out, Context, 0, Policy, Indentation);
}
prettyPrintAttributes(D);
}
void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
@ -624,6 +633,7 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
if (D->hasCXXDirectInitializer())
Out << ")";
}
prettyPrintAttributes(D);
}
void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) {

View File

@ -98,6 +98,7 @@ namespace {
virtual void writePCHReadArgs(raw_ostream &OS) const = 0;
virtual void writePCHReadDecls(raw_ostream &OS) const = 0;
virtual void writePCHWrite(raw_ostream &OS) const = 0;
virtual void writeValue(raw_ostream &OS) const = 0;
};
class SimpleArgument : public Argument {
@ -136,6 +137,19 @@ namespace {
OS << " " << WritePCHRecord(type, "SA->get" +
std::string(getUpperName()) + "()");
}
void writeValue(raw_ostream &OS) const {
if (type == "FunctionDecl *") {
OS << "\" << get" << getUpperName() << "()->getNameInfo().getAsString() << \"";
} else if (type == "IdentifierInfo *") {
OS << "\" << get" << getUpperName() << "()->getName() << \"";
} else if (type == "QualType") {
OS << "\" << get" << getUpperName() << "().getAsString() << \"";
} else if (type == "SourceLocation") {
OS << "\" << get" << getUpperName() << "().getRawEncoding() << \"";
} else {
OS << "\" << get" << getUpperName() << "() << \"";
}
}
};
class StringArgument : public Argument {
@ -190,6 +204,9 @@ namespace {
void writePCHWrite(raw_ostream &OS) const {
OS << " AddString(SA->get" << getUpperName() << "(), Record);\n";
}
void writeValue(raw_ostream &OS) const {
OS << "\\\"\" << get" << getUpperName() << "() << \"\\\"";
}
};
class AlignedArgument : public Argument {
@ -293,6 +310,9 @@ namespace {
OS << " AddTypeSourceInfo(SA->get" << getUpperName()
<< "Type(), Record);\n";
}
void writeValue(raw_ostream &OS) const {
OS << "\" << get" << getUpperName() << "(Ctx) << \"";
}
};
class VariadicArgument : public Argument {
@ -362,6 +382,18 @@ namespace {
<< getLowerName() << "_end(); i != e; ++i)\n";
OS << " " << WritePCHRecord(type, "(*i)");
}
void writeValue(raw_ostream &OS) const {
OS << "\";\n";
OS << " bool isFirst = true;\n"
<< " for (" << getAttrName() << "Attr::" << getLowerName()
<< "_iterator i = " << getLowerName() << "_begin(), e = "
<< getLowerName() << "_end(); i != e; ++i) {\n"
<< " if (isFirst) isFirst = false;\n"
<< " else OS << \", \";\n"
<< " OS << *i;\n"
<< " }\n";
OS << " OS << \"";
}
};
class EnumArgument : public Argument {
@ -422,6 +454,9 @@ namespace {
void writePCHWrite(raw_ostream &OS) const {
OS << "Record.push_back(SA->get" << getUpperName() << "());\n";
}
void writeValue(raw_ostream &OS) const {
OS << "\" << get" << getUpperName() << "() << \"";
}
};
class VersionArgument : public Argument {
@ -463,6 +498,9 @@ namespace {
void writePCHWrite(raw_ostream &OS) const {
OS << " AddVersionTuple(SA->get" << getUpperName() << "(), Record);\n";
}
void writeValue(raw_ostream &OS) const {
OS << getLowerName() << "=\" << get" << getUpperName() << "() << \"";
}
};
}
@ -511,6 +549,15 @@ static Argument *createArgument(Record &Arg, StringRef Attr,
return Ptr;
}
static void writeAvailabilityValue(raw_ostream &OS) {
OS << "\" << getPlatform()->getName();\n"
<< " if (!getIntroduced().empty()) OS << \", introduced=\" << getIntroduced();\n"
<< " if (!getDeprecated().empty()) OS << \", deprecated=\" << getDeprecated();\n"
<< " if (!getObsoleted().empty()) OS << \", obsoleted=\" << getObsoleted();\n"
<< " if (getUnavailable()) OS << \", unavailable\";\n"
<< " OS << \"";
}
void ClangAttrClassEmitter::run(raw_ostream &OS) {
OS << "// This file is generated by TableGen. Do not edit.\n\n";
OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n";
@ -571,6 +618,7 @@ void ClangAttrClassEmitter::run(raw_ostream &OS) {
OS << " }\n\n";
OS << " virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n";
OS << " virtual void printPretty(llvm::raw_ostream &OS, ASTContext &Ctx) const;\n";
for (ai = Args.begin(); ai != ae; ++ai) {
(*ai)->writeAccessors(OS);
@ -600,6 +648,7 @@ void ClangAttrImplEmitter::run(raw_ostream &OS) {
for (; i != e; ++i) {
Record &R = **i;
std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
std::vector<StringRef> Spellings = getValueAsListOfStrings(R, "Spellings");
std::vector<Argument*> Args;
for (ri = ArgRecords.begin(), re = ArgRecords.end(); ri != re; ++ri)
Args.push_back(createArgument(**ri, R.getName()));
@ -615,6 +664,24 @@ void ClangAttrImplEmitter::run(raw_ostream &OS) {
(*ai)->writeCloneArgs(OS);
}
OS << ");\n}\n\n";
OS << "void " << R.getName() << "Attr::printPretty("
<< "llvm::raw_ostream &OS, ASTContext &Ctx) const {\n";
if (Spellings.begin() != Spellings.end()) {
OS << " OS << \" __attribute__((" << *Spellings.begin();
if (Args.size()) OS << "(";
if (*Spellings.begin()=="availability") {
writeAvailabilityValue(OS);
} else {
for (ai = Args.begin(); ai != ae; ++ai) {
if (ai!=Args.begin()) OS <<", ";
(*ai)->writeValue(OS);
}
}
if (Args.size()) OS << ")";
OS << "))\";\n";
}
OS << "}\n\n";
}
}