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


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145002 91177308-0d34-0410-b5e6-96231b3b80d8
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 @@
     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 @@
       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 @@
     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 @@
       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 @@
          << 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 @@
     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 @@
     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 @@
   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 @@
     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 @@
   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 @@
       (*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";
   }
 }