This patch refactors the code that checks whether a file has just been included for the first time.
The `HeaderSearch::FirstTimeLexingFile` function is removed and the information is threaded to the original call site from `HeaderSearch::ShouldEnterIncludeFile`. This will make it possible to avoid tracking the number of includes in a follow up patch.
Depends on D114092.
Reviewed By: dexonsmith
Differential Revision: https://reviews.llvm.org/D114093
/// \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.
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.
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;
/// 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;
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.
///
/// 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.
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);
// Increment the number of times this file has been included.
++FileInfo.NumIncludes;
+ IsFirstIncludeOfFile = FileInfo.NumIncludes == 1;
+
return true;
}
/// 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());
/// 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.
/// 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");
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.
}
// 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.
/// 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;
CodeCompletionFileLoc.getLocWithOffset(CodeCompletionOffset);
}
- EnterSourceFileWithLexer(new Lexer(FID, *InputFile, *this), CurDir);
+ EnterSourceFileWithLexer(
+ new Lexer(FID, *InputFile, *this, IsFirstIncludeOfFile), CurDir);
return false;
}
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