Refactor the paths used for checking and getting the spelling of #include
filenames (and also '#pragma GCC dependency' of course).  Now, assuming
no cleaning is needed, we can go all the way from lexing the filename to
doing filename lookups with no mallocs.  This speeds up user PP time from
0.077 to 0.075s for Cocoa.h (2.6%).

llvm-svn: 39092
diff --git a/clang/Lex/Lexer.cpp b/clang/Lex/Lexer.cpp
index 8b783d6..4892a21 100644
--- a/clang/Lex/Lexer.cpp
+++ b/clang/Lex/Lexer.cpp
@@ -884,7 +884,7 @@
 
 /// LexIncludeFilename - After the preprocessor has parsed a #include, lex and
 /// (potentially) macro expand the filename.
-std::string Lexer::LexIncludeFilename(LexerToken &FilenameTok) {
+void Lexer::LexIncludeFilename(LexerToken &FilenameTok) {
   assert(ParsingPreprocessorDirective &&
          ParsingFilename == false &&
          "Must be in a preprocessing directive!");
@@ -895,46 +895,12 @@
   // Lex the filename.
   Lex(FilenameTok);
 
-  // We should have gotten the filename now.
+  // We should have obtained the filename now.
   ParsingFilename = false;
-
+  
   // No filename?
-  if (FilenameTok.getKind() == tok::eom) {
+  if (FilenameTok.getKind() == tok::eom)
     Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
-    return "";
-  }
-  
-  // Get the text form of the filename.
-  std::string Filename = PP.getSpelling(FilenameTok);
-  assert(!Filename.empty() && "Can't have tokens with empty spellings!");
-  
-  // Make sure the filename is <x> or "x".
-  if (Filename[0] == '<') {
-    if (Filename[Filename.size()-1] != '>') {
-      Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
-      FilenameTok.setKind(tok::eom);
-      return "";
-    }
-  } else if (Filename[0] == '"') {
-    if (Filename[Filename.size()-1] != '"') {
-      Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
-      FilenameTok.setKind(tok::eom);
-      return "";
-    }
-  } else {
-    Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
-    FilenameTok.setKind(tok::eom);
-    return "";
-  }
-  
-  // Diagnose #include "" as invalid.
-  if (Filename.size() == 2) {
-    Diag(FilenameTok.getLocation(), diag::err_pp_empty_filename);
-    FilenameTok.setKind(tok::eom);
-    return "";
-  }
-        
-  return Filename;
 }
 
 /// ReadToEndOfLine - Read the rest of the current preprocessor line as an
diff --git a/clang/Lex/Pragma.cpp b/clang/Lex/Pragma.cpp
index a535cc45..2dd4d6f 100644
--- a/clang/Lex/Pragma.cpp
+++ b/clang/Lex/Pragma.cpp
@@ -18,6 +18,7 @@
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallVector.h"
 using namespace llvm;
 using namespace clang;
 
@@ -246,20 +247,27 @@
 ///
 void Preprocessor::HandlePragmaDependency(LexerToken &DependencyTok) {
   LexerToken FilenameTok;
-  std::string Filename = CurLexer->LexIncludeFilename(FilenameTok);
+  CurLexer->LexIncludeFilename(FilenameTok);
 
   // If the token kind is EOM, the error has already been diagnosed.
   if (FilenameTok.getKind() == tok::eom)
     return;
   
-  // Find out whether the filename is <x> or "x".
-  bool isAngled = Filename[0] == '<';
+  // Reserve a buffer to get the spelling.
+  SmallVector<char, 128> FilenameBuffer;
+  FilenameBuffer.resize(FilenameTok.getLength());
+  
+  const char *FilenameStart = &FilenameBuffer[0], *FilenameEnd;
+  bool isAngled = GetIncludeFilenameSpelling(FilenameTok,
+                                             FilenameStart, FilenameEnd);
+  // If GetIncludeFilenameSpelling set the start ptr to null, there was an
+  // error.
+  if (FilenameStart == 0)
+    return;
   
   // Search include directories for this file.
   const DirectoryLookup *CurDir;
-
-  // Remove the quotes.
-  const FileEntry *File = LookupFile(&Filename[1], &Filename[Filename.size()-1],
+  const FileEntry *File = LookupFile(FilenameStart, FilenameEnd,
                                      isAngled, 0, CurDir);
   if (File == 0)
     return Diag(FilenameTok, diag::err_pp_file_not_found);
diff --git a/clang/Lex/Preprocessor.cpp b/clang/Lex/Preprocessor.cpp
index 8ee524f..09fa7c1 100644
--- a/clang/Lex/Preprocessor.cpp
+++ b/clang/Lex/Preprocessor.cpp
@@ -1474,6 +1474,55 @@
 // Preprocessor Include Directive Handling.
 //===----------------------------------------------------------------------===//
 
+/// GetIncludeFilenameSpelling - Turn the specified lexer token into a fully
+/// checked and spelled filename, e.g. as an operand of #include. This returns
+/// true if the input filename was in <>'s or false if it were in ""'s.  The
+/// caller is expected to provide a buffer that is large enough to hold the
+/// spelling of the filename, but is also expected to handle the case when
+/// this method decides to use a different buffer.
+bool Preprocessor::GetIncludeFilenameSpelling(const LexerToken &FilenameTok,
+                                              const char *&BufStart,
+                                              const char *&BufEnd) {
+  // Get the text form of the filename.
+  unsigned Len = getSpelling(FilenameTok, BufStart);
+  BufEnd = BufStart+Len;
+  assert(BufStart != BufEnd && "Can't have tokens with empty spellings!");
+  
+  // Make sure the filename is <x> or "x".
+  bool isAngled;
+  if (BufStart[0] == '<') {
+    if (BufEnd[-1] != '>') {
+      Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
+      BufStart = 0;
+      return true;
+    }
+    isAngled = true;
+  } else if (BufStart[0] == '"') {
+    if (BufEnd[-1] != '"') {
+      Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
+      BufStart = 0;
+      return true;
+    }
+    isAngled = false;
+  } else {
+    Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
+    BufStart = 0;
+    return true;
+  }
+  
+  // Diagnose #include "" as invalid.
+  if (BufEnd-BufStart <= 2) {
+    Diag(FilenameTok.getLocation(), diag::err_pp_empty_filename);
+    BufStart = 0;
+    return "";
+  }
+  
+  // Skip the brackets.
+  ++BufStart;
+  --BufEnd;
+  return isAngled;
+}
+
 /// HandleIncludeDirective - The "#include" tokens have just been read, read the
 /// file to be included from the lexer, then include it!  This is a common
 /// routine with functionality shared between #include, #include_next and
@@ -1483,12 +1532,24 @@
                                           bool isImport) {
 
   LexerToken FilenameTok;
-  std::string Filename = CurLexer->LexIncludeFilename(FilenameTok);
+  CurLexer->LexIncludeFilename(FilenameTok);
   
   // If the token kind is EOM, the error has already been diagnosed.
   if (FilenameTok.getKind() == tok::eom)
     return;
   
+  // Reserve a buffer to get the spelling.
+  SmallVector<char, 128> FilenameBuffer;
+  FilenameBuffer.resize(FilenameTok.getLength());
+  
+  const char *FilenameStart = &FilenameBuffer[0], *FilenameEnd;
+  bool isAngled = GetIncludeFilenameSpelling(FilenameTok,
+                                             FilenameStart, FilenameEnd);
+  // If GetIncludeFilenameSpelling set the start ptr to null, there was an
+  // error.
+  if (FilenameStart == 0)
+    return;
+  
   // Verify that there is nothing after the filename, other than EOM.  Use the
   // preprocessor to lex this in case lexing the filename entered a macro.
   CheckEndOfDirective("#include");
@@ -1497,13 +1558,9 @@
   if (IncludeMacroStack.size() == MaxAllowedIncludeStackDepth-1)
     return Diag(FilenameTok, diag::err_pp_include_too_deep);
   
-  // Find out whether the filename is <x> or "x".
-  bool isAngled = Filename[0] == '<';
-  
   // Search include directories.
   const DirectoryLookup *CurDir;
-  // Remove the quotes from the filename.
-  const FileEntry *File = LookupFile(&Filename[1], &Filename[Filename.size()-1],
+  const FileEntry *File = LookupFile(FilenameStart, FilenameEnd,
                                      isAngled, LookupFrom, CurDir);
   if (File == 0)
     return Diag(FilenameTok, diag::err_pp_file_not_found);
diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h
index 94a94d3..eb55331 100644
--- a/clang/include/clang/Lex/Lexer.h
+++ b/clang/include/clang/Lex/Lexer.h
@@ -341,9 +341,8 @@
   
   /// LexIncludeFilename - After the preprocessor has parsed a #include, lex and
   /// (potentially) macro expand the filename.  If the sequence parsed is not
-  /// lexically legal, emit a diagnostic and return a result EOM token.  Return
-  /// the spelled and checked filename.
-  std::string LexIncludeFilename(LexerToken &Result);
+  /// lexically legal, emit a diagnostic and return a result EOM token.
+  void LexIncludeFilename(LexerToken &Result);
 };
 
 
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index e999a8b..1e52a4b 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -403,6 +403,15 @@
   /// start lexing tokens from it instead of the current buffer.
   void EnterSourceFileWithLexer(Lexer *TheLexer, const DirectoryLookup *Dir);
   
+  /// GetIncludeFilenameSpelling - Turn the specified lexer token into a fully
+  /// checked and spelled filename, e.g. as an operand of #include. This returns
+  /// true if the input filename was in <>'s or false if it were in ""'s.  The
+  /// caller is expected to provide a buffer that is large enough to hold the
+  /// spelling of the filename, but is also expected to handle the case when
+  /// this method decides to use a different buffer.
+  bool GetIncludeFilenameSpelling(const LexerToken &FNTok,
+                                  const char *&BufStart, const char *&BufEnd);
+  
   /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
   /// return null on failure.  isAngled indicates whether the file reference is
   /// for system #include's or not (i.e. using <> instead of "").