diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -443,8 +443,8 @@ /// \return false if \#including the file will have no effect or true /// if we should include it. bool ShouldEnterIncludeFile(Preprocessor &PP, const FileEntry *File, - bool isImport, bool ModulesEnabled, - Module *M); + bool isImport, bool ModulesEnabled, Module *M, + bool &IsFirstIncludeOfFile); /// Return whether the specified file is a normal header, /// a system header, or a C++ friendly system header. @@ -489,11 +489,6 @@ getFileInfo(File).ControllingMacro = ControllingMacro; } - /// Return true if this is the first time encountering this header. - bool FirstTimeLexingFile(const FileEntry *File) { - return getFileInfo(File).NumIncludes == 1; - } - /// Determine whether this file is intended to be safe from /// multiple inclusions, e.g., it has \#pragma once or a controlling /// macro. diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h --- a/clang/include/clang/Lex/Lexer.h +++ b/clang/include/clang/Lex/Lexer.h @@ -128,6 +128,9 @@ bool HasLeadingEmptyMacro; + /// True if this is the first time we're lexing the input file. + bool IsFirstTimeLexingFile; + // NewLinePtr - A pointer to new line character '\n' being lexed. For '\r\n', // it also points to '\n.' const char *NewLinePtr; @@ -142,19 +145,22 @@ /// with the specified preprocessor managing the lexing process. This lexer /// assumes that the associated file buffer and Preprocessor objects will /// outlive it, so it doesn't take ownership of either of them. - Lexer(FileID FID, const llvm::MemoryBufferRef &InputFile, Preprocessor &PP); + Lexer(FileID FID, const llvm::MemoryBufferRef &InputFile, Preprocessor &PP, + bool IsFirstIncludeOfFile = true); /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the /// text range will outlive it, so it doesn't take ownership of it. Lexer(SourceLocation FileLoc, const LangOptions &LangOpts, - const char *BufStart, const char *BufPtr, const char *BufEnd); + const char *BufStart, const char *BufPtr, const char *BufEnd, + bool IsFirstIncludeOfFile = true); /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the /// text range will outlive it, so it doesn't take ownership of it. Lexer(FileID FID, const llvm::MemoryBufferRef &FromFile, - const SourceManager &SM, const LangOptions &LangOpts); + const SourceManager &SM, const LangOptions &LangOpts, + bool IsFirstIncludeOfFile = true); Lexer(const Lexer &) = delete; Lexer &operator=(const Lexer &) = delete; @@ -563,6 +569,9 @@ static StringRef getIndentationForLine(SourceLocation Loc, const SourceManager &SM); + /// Check if this is the first time we're lexing the input file. + bool isFirstTimeLexingFile() const { return IsFirstTimeLexingFile; } + private: //===--------------------------------------------------------------------===// // Internal implementation interfaces. diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -1368,7 +1368,7 @@ /// /// Emits a diagnostic, doesn't enter the file, and returns true on error. bool EnterSourceFile(FileID FID, const DirectoryLookup *Dir, - SourceLocation Loc); + SourceLocation Loc, bool IsFirstIncludeOfFile = true); /// Add a Macro to the top of the include stack and start lexing /// tokens from it instead of the current buffer. diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -1310,9 +1310,12 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, const FileEntry *File, bool isImport, - bool ModulesEnabled, Module *M) { + bool ModulesEnabled, Module *M, + bool &IsFirstIncludeOfFile) { ++NumIncluded; // Count # of attempted #includes. + IsFirstIncludeOfFile = false; + // Get information about this file. HeaderFileInfo &FileInfo = getFileInfo(File); @@ -1387,6 +1390,8 @@ // Increment the number of times this file has been included. ++FileInfo.NumIncludes; + IsFirstIncludeOfFile = FileInfo.NumIncludes == 1; + return true; } diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -133,10 +133,10 @@ /// assumes that the associated file buffer and Preprocessor objects will /// outlive it, so it doesn't take ownership of either of them. Lexer::Lexer(FileID FID, const llvm::MemoryBufferRef &InputFile, - Preprocessor &PP) + Preprocessor &PP, bool IsFirstIncludeOfFile) : PreprocessorLexer(&PP, FID), FileLoc(PP.getSourceManager().getLocForStartOfFile(FID)), - LangOpts(PP.getLangOpts()) { + LangOpts(PP.getLangOpts()), IsFirstTimeLexingFile(IsFirstIncludeOfFile) { InitLexer(InputFile.getBufferStart(), InputFile.getBufferStart(), InputFile.getBufferEnd()); @@ -147,8 +147,10 @@ /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. Lexer::Lexer(SourceLocation fileloc, const LangOptions &langOpts, - const char *BufStart, const char *BufPtr, const char *BufEnd) - : FileLoc(fileloc), LangOpts(langOpts) { + const char *BufStart, const char *BufPtr, const char *BufEnd, + bool IsFirstIncludeOfFile) + : FileLoc(fileloc), LangOpts(langOpts), + IsFirstTimeLexingFile(IsFirstIncludeOfFile) { InitLexer(BufStart, BufPtr, BufEnd); // We *are* in raw mode. @@ -159,9 +161,11 @@ /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. Lexer::Lexer(FileID FID, const llvm::MemoryBufferRef &FromFile, - const SourceManager &SM, const LangOptions &langOpts) + const SourceManager &SM, const LangOptions &langOpts, + bool IsFirstIncludeOfFile) : Lexer(SM.getLocForStartOfFile(FID), langOpts, FromFile.getBufferStart(), - FromFile.getBufferStart(), FromFile.getBufferEnd()) {} + FromFile.getBufferStart(), FromFile.getBufferEnd(), + IsFirstIncludeOfFile) {} void Lexer::resetExtendedTokenMode() { assert(PP && "Cannot reset token mode without a preprocessor"); diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -2143,12 +2143,14 @@ IsImportDecl || IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import; + bool IsFirstIncludeOfFile = false; + // Ask HeaderInfo if we should enter this #include file. If not, #including // this file will have no effect. if (Action == Enter && File && - !HeaderInfo.ShouldEnterIncludeFile(*this, &File->getFileEntry(), - EnterOnce, getLangOpts().Modules, - SuggestedModule.getModule())) { + !HeaderInfo.ShouldEnterIncludeFile( + *this, &File->getFileEntry(), EnterOnce, getLangOpts().Modules, + SuggestedModule.getModule(), IsFirstIncludeOfFile)) { // Even if we've already preprocessed this header once and know that we // don't need to see its contents again, we still need to import it if it's // modular because we might not have imported it from this submodule before. @@ -2340,7 +2342,8 @@ } // If all is good, enter the new file! - if (EnterSourceFile(FID, CurDir, FilenameTok.getLocation())) + if (EnterSourceFile(FID, CurDir, FilenameTok.getLocation(), + IsFirstIncludeOfFile)) return {ImportAction::None}; // Determine if we're switching to building a new submodule, and which one. diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -67,7 +67,8 @@ /// EnterSourceFile - Add a source file to the top of the include stack and /// start lexing tokens from it instead of the current buffer. bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, - SourceLocation Loc) { + SourceLocation Loc, + bool IsFirstIncludeOfFile) { assert(!CurTokenLexer && "Cannot #include a file inside a macro!"); ++NumEnteredSourceFiles; @@ -91,7 +92,8 @@ CodeCompletionFileLoc.getLocWithOffset(CodeCompletionOffset); } - EnterSourceFileWithLexer(new Lexer(FID, *InputFile, *this), CurDir); + EnterSourceFileWithLexer( + new Lexer(FID, *InputFile, *this, IsFirstIncludeOfFile), CurDir); return false; } @@ -377,7 +379,7 @@ CurPPLexer->MIOpt.GetDefinedMacro()) { if (!isMacroDefined(ControllingMacro) && DefinedMacro != ControllingMacro && - HeaderInfo.FirstTimeLexingFile(FE)) { + CurLexer->isFirstTimeLexingFile()) { // If the edit distance between the two macros is more than 50%, // DefinedMacro may not be header guard, or can be header guard of