diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index cf2e3c5d25b6..345cc945103d 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -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 #include #include @@ -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; } }; diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 1553af1b130d..e5b4b0431b1f 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -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& 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()) - Proto += " __attribute((noreturn))"; - - if (D->hasAttr()) - Proto += " __attribute((returns_twice))"; - if (CXXConstructorDecl *CDecl = dyn_cast(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) { diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 5c236be559f1..03b6f76e46af 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -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 ArgRecords = R.getValueAsListOfDefs("Args"); + std::vector Spellings = getValueAsListOfStrings(R, "Spellings"); std::vector 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"; } }