Introduce a -cc1-level option -pubnames-dump, which simply dumps the
list of identifiers that that 'public' names at the end of the
translation unit, e.g., defined macros or identifiers with top-level
names, in sorted order. Meant to support <rdar://problem/10921596>.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153522 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 973c5a4..1dd501e 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -425,6 +425,7 @@
   case frontend::PrintDeclContext:       return "-print-decl-contexts";
   case frontend::PrintPreamble:          return "-print-preamble";
   case frontend::PrintPreprocessedInput: return "-E";
+  case frontend::PubnamesDump:           return "-pubnames-dump";
   case frontend::RewriteMacros:          return "-rewrite-macros";
   case frontend::RewriteObjC:            return "-rewrite-objc";
   case frontend::RewriteTest:            return "-rewrite-test";
@@ -1360,6 +1361,8 @@
       Opts.ProgramAction = frontend::PrintPreamble; break;
     case OPT_E:
       Opts.ProgramAction = frontend::PrintPreprocessedInput; break;
+    case OPT_pubnames_dump:
+      Opts.ProgramAction = frontend::PubnamesDump; break;
     case OPT_rewrite_macros:
       Opts.ProgramAction = frontend::RewriteMacros; break;
     case OPT_rewrite_objc:
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 737ee4a..b4a439d 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -25,6 +25,7 @@
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/system_error.h"
+#include <set>
 
 using namespace clang;
 
@@ -354,6 +355,77 @@
   return new ASTConsumer();
 }
 
+namespace {
+  class PubnamesDumpConsumer : public ASTConsumer {
+    Preprocessor &PP;
+    
+    /// \brief Determine whether the given identifier provides a 'public' name.
+    bool isPublicName(IdentifierInfo *II) {
+      // If there are any top-level declarations associated with this
+      // identifier, it is a public name.
+      if (II->getFETokenInfo<void>())
+        return true;
+
+      // If this identifier is the name of a non-builtin macro that isn't
+      // defined on the command line or implicitly by the front end, it is a
+      // public name.
+      if (II->hasMacroDefinition()) {
+        if (MacroInfo *M = PP.getMacroInfo(II))
+          if (!M->isBuiltinMacro()) {
+            SourceLocation Loc = M->getDefinitionLoc();
+            FileID File = PP.getSourceManager().getFileID(Loc);
+            if (PP.getSourceManager().getFileEntryForID(File))
+              return true;
+          }
+      }
+      
+      return false;
+    }
+      
+  public:
+    PubnamesDumpConsumer(Preprocessor &PP) : PP(PP) { }
+        
+    virtual void HandleTranslationUnit(ASTContext &Ctx) {
+      std::set<StringRef> Pubnames;
+      
+      // Add the names of any non-builtin macros.
+      for (IdentifierTable::iterator I = Ctx.Idents.begin(),
+                                  IEnd = Ctx.Idents.end();
+           I != IEnd; ++I) {
+        if (isPublicName(I->second))
+          Pubnames.insert(I->first());
+      }
+      
+      // If there is an external identifier lookup source, consider those
+      // identifiers as well.
+      if (IdentifierInfoLookup *External
+            = Ctx.Idents.getExternalIdentifierLookup()) {
+        OwningPtr<IdentifierIterator> Iter(External->getIdentifiers());
+        do {
+          StringRef Name = Iter->Next();
+          if (Name.empty())
+            break;
+          
+          if (isPublicName(PP.getIdentifierInfo(Name)))
+            Pubnames.insert(Name);
+        } while (true);
+      }
+
+      // Print the names, in lexicographical order.
+      for (std::set<StringRef>::iterator N = Pubnames.begin(),
+                                      NEnd = Pubnames.end();
+           N != NEnd; ++N) {
+        llvm::outs() << *N << '\n';
+      }
+    }
+  };
+}
+
+ASTConsumer *PubnamesDumpAction::CreateASTConsumer(CompilerInstance &CI,
+                                                   StringRef InFile) {
+  return new PubnamesDumpConsumer(CI.getPreprocessor());
+}
+
 //===----------------------------------------------------------------------===//
 // Preprocessor Actions
 //===----------------------------------------------------------------------===//