On 2011.11.07 20:00, Douglas Gregor wrote:
> 
> On Nov 4, 2011, at 7:44 AM, Richard Membarth wrote:
> 
> > Attached is a patch that adds support for pretty-printing attributes
> > stored in the AST. Tblgen is used to generate the necessary code for
> > pretty printing attributes as suggest by Peter in [1].
> > 
> > Please let me know if this is ok.
> 
> 
> This generally looks good. My only non-trivial comment is that this printing 
> assumes that all of the attributes can be pretty-printed by just printing the 
> arguments as a comma-separated list, but I doubt that's actually the case. If 
> nothing else, the printing of VersionArguments looks incorrect for the 
> "availability" attribute. It would be better to have some way to escape out 
> to hand-written printing code, and then implement that code for the cases 
> where the default comma-separated list printing doesn't work.

I looked into this today and updated the patch, which is attached to
this mail. Printing of VersionArguments was indeed not correct. I
added a check to call a separate hand-written pretty printing
function for the "availability" attribute. The same can be done in
case other attributes need a similar special handling.
I hope this is now sufficient for pretty printing the currently
available C/C++ attributes.

> 
> One minor thing:
> 
> @@ -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"
> 
> Shouldn't this be if(isFirst)?

Yes, this is also updated in the patch.

Richard

> 
> +         << "    OS << *i;\n"
> +         << "  }\n";
> +      OS << "  OS << \"";
> +    }
>    };
> 
> 
> 
>       - Doug

diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index cf2e3c5..345cc94 100644
--- a/include/clang/AST/Attr.h
+++ b/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 <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; }
 };
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 1553af1..e5b4b04 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/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<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) {
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index 5c236be..03b6f76 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/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<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";
   }
 }
 

Attachment: signature.asc
Description: Digital signature

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to