]> granicus.if.org Git - clang/commitdiff
Add an implementation of -dM that follows GCC closely enough to permit
authorChris Lattner <sabre@nondot.org>
Fri, 6 Feb 2009 06:45:26 +0000 (06:45 +0000)
committerChris Lattner <sabre@nondot.org>
Fri, 6 Feb 2009 06:45:26 +0000 (06:45 +0000)
diffing the output of:
  clang -dM -o - -E -x c foo.c | sort

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63926 91177308-0d34-0410-b5e6-96231b3b80d8

Driver/PrintPreprocessedOutput.cpp
include/clang/Lex/MacroInfo.h
lib/Lex/Preprocessor.cpp
test/Preprocessor/dump_macros.c [new file with mode: 0644]

index 8b73c14d4d802f44679e76353e3ab5df28fbe789..8bd4e96ae3bafc8f211b2c6a9c8731e54ce42703 100644 (file)
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang.h"
+#include "clang/Lex/MacroInfo.h"
 #include "clang/Lex/PPCallbacks.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/Pragma.h"
@@ -39,6 +40,10 @@ static llvm::cl::opt<bool>
 EnableMacroCommentOutput("CC",
                          llvm::cl::desc("Enable comment output in -E mode, "
                                         "even from macro expansions"));
+static llvm::cl::opt<bool>
+DumpMacros("dM", llvm::cl::desc("Print macro definitions in -E mode instead of"
+                                " normal output"));
+
 
 namespace {
 class PrintPPOutputPPCallbacks : public PPCallbacks {
@@ -543,6 +548,49 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
   }
 }
 
+/// PrintMacroDefinition - Print a macro definition in a form that will be
+/// properly accepted back as a definition.
+static void PrintMacroDefinition(IdentifierInfo &II, const MacroInfo &MI,
+                                 Preprocessor &PP, llvm::raw_ostream &OS) {
+  // Ignore computed macros like __LINE__ and friends. 
+  if (MI.isBuiltinMacro()) return;
+  OS << "#define " << II.getName();
+
+  if (MI.isFunctionLike()) {
+    OS << '(';
+    if (MI.arg_empty())
+      ;
+    else if (MI.getNumArgs() == 1) 
+      OS << (*MI.arg_begin())->getName();
+    else {
+      MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end();
+      OS << (*AI++)->getName();
+      while (AI != E)
+        OS << ',' << (*AI++)->getName();
+    }
+    
+    if (MI.isVariadic()) {
+      if (!MI.arg_empty())
+        OS << ',';
+      OS << "...";
+    }
+    OS << ')';
+  }
+  
+  // GCC always emits a space, even if the macro body is empty.  However, do not
+  // want to emit two spaces if the first token has a leading space.
+  if (MI.tokens_empty() || !MI.tokens_begin()->hasLeadingSpace())
+    OS << ' ';
+  
+  for (MacroInfo::tokens_iterator I = MI.tokens_begin(), E = MI.tokens_end();
+       I != E; ++I) {
+    if (I->hasLeadingSpace())
+      OS << ' ';
+    OS << PP.getSpelling(*I);
+  }
+  OS << "\n";
+}
+
 
 /// DoPrintPreprocessedInput - This implements -E mode.
 ///
@@ -564,31 +612,45 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP,
   
   OS.SetBufferSize(64*1024);
   
-  Token Tok;
-  PrintPPOutputPPCallbacks *Callbacks;
-  Callbacks = new PrintPPOutputPPCallbacks(PP, OS);
-  PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks));
-  PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",Callbacks));
-
-  PP.setPPCallbacks(Callbacks);
-
-  // After we have configured the preprocessor, enter the main file.
-  
-  // Start parsing the specified input file.
-  PP.EnterMainSourceFile();
-
-  // Consume all of the tokens that come from the predefines buffer.  Those
-  // should not be emitted into the output and are guaranteed to be at the
-  // start.
-  const SourceManager &SourceMgr = PP.getSourceManager();
-  do PP.Lex(Tok);
-  while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() &&
-         !strcmp(SourceMgr.getPresumedLoc(Tok.getLocation()).getFilename(),
-                 "<predefines>"));
-
-  // Read all the preprocessed tokens, printing them out to the stream.
-  PrintPreprocessedTokens(PP, Tok, Callbacks, OS);
-  OS << '\n';
+  if (DumpMacros) {
+    // -dM mode just scans and ignores all tokens in the files, then dumps out
+    // the macro table at the end.
+    PP.EnterMainSourceFile();
+    
+    Token Tok;
+    do PP.Lex(Tok);
+    while (Tok.isNot(tok::eof));
+    
+    for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
+         I != E; ++I)
+      PrintMacroDefinition(*I->first, *I->second, PP, OS);
+    
+  } else {
+    PrintPPOutputPPCallbacks *Callbacks;
+    Callbacks = new PrintPPOutputPPCallbacks(PP, OS);
+    PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks));
+    PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",
+                                                        Callbacks));
+
+    PP.setPPCallbacks(Callbacks);
+
+    // After we have configured the preprocessor, enter the main file.
+    PP.EnterMainSourceFile();
+
+    // Consume all of the tokens that come from the predefines buffer.  Those
+    // should not be emitted into the output and are guaranteed to be at the
+    // start.
+    const SourceManager &SourceMgr = PP.getSourceManager();
+    Token Tok;
+    do PP.Lex(Tok);
+    while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() &&
+           !strcmp(SourceMgr.getPresumedLoc(Tok.getLocation()).getFilename(),
+                   "<predefines>"));
+
+    // Read all the preprocessed tokens, printing them out to the stream.
+    PrintPreprocessedTokens(PP, Tok, Callbacks, OS);
+    OS << '\n';
+  }
   
   // Flush the ostream.
   OS.flush();
index c63b701a85cdf846f2b2df2a1c2136a5004f5476..7e0125f496d04dfad401c47393bde74741bfca89 100644 (file)
@@ -116,6 +116,7 @@ public:
   /// Arguments - The list of arguments for a function-like macro.  This can be
   /// empty, for, e.g. "#define X()".
   typedef IdentifierInfo* const *arg_iterator;
+  bool arg_empty() const { return NumArguments == 0; }
   arg_iterator arg_begin() const { return ArgumentList; }
   arg_iterator arg_end() const { return ArgumentList+NumArguments; }
   unsigned getNumArgs() const { return NumArguments; }
@@ -163,6 +164,7 @@ public:
   typedef llvm::SmallVector<Token, 8>::const_iterator tokens_iterator;
   tokens_iterator tokens_begin() const { return ReplacementTokens.begin(); }
   tokens_iterator tokens_end() const { return ReplacementTokens.end(); }
+  bool tokens_empty() const { return ReplacementTokens.empty(); }
   
   /// AddTokenToBody - Add the specified token to the replacement text for the
   /// macro.
index 9b5965ccc51b5195bcf21a4418d98c8b7a4f3b9b..984cf1aab82923e3bdbcf8f9694f14e97850aaa7 100644 (file)
@@ -13,7 +13,7 @@
 //
 // Options to support:
 //   -H       - Print the name of each header file used.
-//   -d[MDNI] - Dump various things.
+//   -d[DNI] - Dump various things.
 //   -fworking-directory - #line's with preprocessor's working dir.
 //   -fpreprocessed
 //   -dependency-file,-M,-MM,-MF,-MG,-MP,-MT,-MQ,-MD,-MMD
diff --git a/test/Preprocessor/dump_macros.c b/test/Preprocessor/dump_macros.c
new file mode 100644 (file)
index 0000000..348257f
--- /dev/null
@@ -0,0 +1,31 @@
+// RUN: clang -E -dM %s -o %t &&
+
+// Space even without expansion tokens
+// RUN: grep "#define A(x) " %t &&
+#define A(x)
+
+// Space before expansion list.
+// RUN: grep "#define B(x,y) x y" %t &&
+#define B(x,y)x y
+
+// No space in expansion list.
+// RUN: grep "#define C(x,y) x y" %t &&
+#define C(x, y) x y
+
+// No paste avoidance.
+// RUN: grep "#define X() .." %t &&
+#define X() ..
+
+// Simple test.
+// RUN: grep "#define Y ." %t &&
+// RUN: grep "#define Z X()Y" %t &&
+#define Y .
+#define Z X()Y
+
+// gcc prints macros at end of translation unit, so last one wins.
+// RUN: grep "#define foo 2" %t &&
+// RUN: not grep "#define foo 1" %t
+#define foo 1
+#undef foo
+#define foo 2
+