[frontend] -frewrite-includes: turn implicit module imports into @imports.
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Wed, 10 Apr 2013 01:53:50 +0000 (01:53 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Wed, 10 Apr 2013 01:53:50 +0000 (01:53 +0000)
rdar://13610250

llvm-svn: 179145

clang/lib/Rewrite/Frontend/InclusionRewriter.cpp
clang/test/Frontend/rewrite-includes-modules.c [new file with mode: 0644]

index 5740a84..cbdc702 100644 (file)
@@ -27,10 +27,11 @@ class InclusionRewriter : public PPCallbacks {
   /// Information about which #includes were actually performed,
   /// created by preprocessor callbacks.
   struct FileChange {
+    const Module *Mod;
     SourceLocation From;
     FileID Id;
     SrcMgr::CharacteristicKind FileType;
-    FileChange(SourceLocation From) : From(From) {
+    FileChange(SourceLocation From, const Module *Mod) : Mod(Mod), From(From) {
     }
   };
   Preprocessor &PP; ///< Used to find inclusion directives.
@@ -65,6 +66,7 @@ private:
   void WriteLineInfo(const char *Filename, int Line,
                      SrcMgr::CharacteristicKind FileType,
                      StringRef EOL, StringRef Extra = StringRef());
+  void WriteImplicitModuleImport(const Module *Mod, StringRef EOL);
   void OutputContentUpTo(const MemoryBuffer &FromFile,
                          unsigned &WriteFrom, unsigned WriteTo,
                          StringRef EOL, int &lines,
@@ -117,6 +119,12 @@ void InclusionRewriter::WriteLineInfo(const char *Filename, int Line,
   OS << EOL;
 }
 
+void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod,
+                                                  StringRef EOL) {
+  OS << "@import " << Mod->getFullModuleName() << ";"
+     << " /* clang -frewrite-includes: implicit import */" << EOL;
+}
+
 /// FileChanged - Whenever the preprocessor enters or exits a #include file
 /// it invokes this handler.
 void InclusionRewriter::FileChanged(SourceLocation Loc,
@@ -157,13 +165,14 @@ void InclusionRewriter::InclusionDirective(SourceLocation HashLoc,
                                            const FileEntry * /*File*/,
                                            StringRef /*SearchPath*/,
                                            StringRef /*RelativePath*/,
-                                           const Module * /*Imported*/) {
+                                           const Module *Imported) {
   assert(LastInsertedFileChange == FileChanges.end() && "Another inclusion "
     "directive was found before the previous one was processed");
   std::pair<FileChangeMap::iterator, bool> p = FileChanges.insert(
-    std::make_pair(HashLoc.getRawEncoding(), FileChange(HashLoc)));
+    std::make_pair(HashLoc.getRawEncoding(), FileChange(HashLoc, Imported)));
   assert(p.second && "Unexpected revisitation of the same include directive");
-  LastInsertedFileChange = p.first;
+  if (!Imported)
+    LastInsertedFileChange = p.first;
 }
 
 /// Simple lookup for a SourceLocation (specifically one denoting the hash in
@@ -289,24 +298,24 @@ bool InclusionRewriter::Process(FileID FileId,
           case tok::pp_import: {
             CommentOutDirective(RawLex, HashToken, FromFile, EOL, NextToWrite,
               Line);
+            StringRef LineInfoExtra;
             if (const FileChange *Change = FindFileChangeLocation(
                 HashToken.getLocation())) {
-              // now include and recursively process the file
-              if (Process(Change->Id, Change->FileType)) {
+              if (Change->Mod) {
+                WriteImplicitModuleImport(Change->Mod, EOL);
+
+              // else now include and recursively process the file
+              } else if (Process(Change->Id, Change->FileType)) {
                 // and set lineinfo back to this file, if the nested one was
                 // actually included
                 // `2' indicates returning to a file (after having included
                 // another file.
-                WriteLineInfo(FileName, Line, FileType, EOL, " 2");
-              } else {
-                // fix up lineinfo (since commented out directive changed line
-                // numbers).
-                WriteLineInfo(FileName, Line, FileType, EOL);
+                LineInfoExtra = " 2";
               }
-            } else
-              // fix up lineinfo (since commented out directive changed line
-              // numbers) for inclusions that were skipped due to header guards
-              WriteLineInfo(FileName, Line, FileType, EOL);
+            }
+            // fix up lineinfo (since commented out directive changed line
+            // numbers) for inclusions that were skipped due to header guards
+            WriteLineInfo(FileName, Line, FileType, EOL, LineInfoExtra);
             break;
           }
           case tok::pp_pragma: {
diff --git a/clang/test/Frontend/rewrite-includes-modules.c b/clang/test/Frontend/rewrite-includes-modules.c
new file mode 100644 (file)
index 0000000..783a967
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x objective-c %s -F %S/../Modules/Inputs -E -frewrite-includes -o - | FileCheck %s
+
+int bar();
+#include <Module/Module.h>
+int foo();
+#include <Module/Module.h>
+
+// CHECK: int bar();{{$}}
+// CHECK-NEXT: #if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: #include <Module/Module.h>{{$}}
+// CHECK-NEXT: #endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: @import Module; /* clang -frewrite-includes: implicit import */{{$}}
+// CHECK-NEXT: # 6 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}}
+// CHECK-NEXT: int foo();{{$}}
+// CHECK-NEXT: #if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: #include <Module/Module.h>{{$}}
+// CHECK-NEXT: #endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: @import Module; /* clang -frewrite-includes: implicit import */{{$}}
+// CHECK-NEXT: # 8 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}}