diff options
Diffstat (limited to 'lib/Frontend/Rewrite/InclusionRewriter.cpp')
-rw-r--r-- | lib/Frontend/Rewrite/InclusionRewriter.cpp | 180 |
1 files changed, 57 insertions, 123 deletions
diff --git a/lib/Frontend/Rewrite/InclusionRewriter.cpp b/lib/Frontend/Rewrite/InclusionRewriter.cpp index cb4e773aca87..dcf645f67f2f 100644 --- a/lib/Frontend/Rewrite/InclusionRewriter.cpp +++ b/lib/Frontend/Rewrite/InclusionRewriter.cpp @@ -49,6 +49,8 @@ class InclusionRewriter : public PPCallbacks { std::map<unsigned, const Module *> ModuleIncludes; /// Tracks where inclusions that enter modules (in a module build) are found. std::map<unsigned, const Module *> ModuleEntryIncludes; + /// Tracks where #if and #elif directives get evaluated and whether to true. + std::map<unsigned, bool> IfConditions; /// Used transitively for building up the FileIncludes mapping over the /// various \c PPCallbacks callbacks. SourceLocation LastInclusionLocation; @@ -70,7 +72,7 @@ private: void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID) override; - void FileSkipped(const FileEntry &SkippedFile, const Token &FilenameTok, + void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok, SrcMgr::CharacteristicKind FileType) override; void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, @@ -78,6 +80,10 @@ private: StringRef SearchPath, StringRef RelativePath, const Module *Imported, SrcMgr::CharacteristicKind FileType) override; + void If(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue) override; + void Elif(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue, SourceLocation IfLoc) override; void WriteLineInfo(StringRef Filename, int Line, SrcMgr::CharacteristicKind FileType, StringRef Extra = StringRef()); @@ -89,12 +95,10 @@ private: void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, const MemoryBuffer &FromFile, StringRef EOL, unsigned &NextToWrite, int &Lines); - bool HandleHasInclude(FileID FileId, Lexer &RawLex, - const DirectoryLookup *Lookup, Token &Tok, - bool &FileExists); const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const; const Module *FindModuleAtLocation(SourceLocation Loc) const; const Module *FindEnteredModule(SourceLocation Loc) const; + bool IsIfAtLocationTrue(SourceLocation Loc) const; StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken); }; @@ -169,8 +173,8 @@ void InclusionRewriter::FileChanged(SourceLocation Loc, /// Called whenever an inclusion is skipped due to canonical header protection /// macros. -void InclusionRewriter::FileSkipped(const FileEntry &/*SkippedFile*/, - const Token &/*FilenameTok*/, +void InclusionRewriter::FileSkipped(const FileEntryRef & /*SkippedFile*/, + const Token & /*FilenameTok*/, SrcMgr::CharacteristicKind /*FileType*/) { assert(LastInclusionLocation.isValid() && "A file, that wasn't found via an inclusion directive, was skipped"); @@ -203,6 +207,23 @@ void InclusionRewriter::InclusionDirective(SourceLocation HashLoc, LastInclusionLocation = HashLoc; } +void InclusionRewriter::If(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue) { + auto P = IfConditions.insert( + std::make_pair(Loc.getRawEncoding(), ConditionValue == CVK_True)); + (void)P; + assert(P.second && "Unexpected revisitation of the same if directive"); +} + +void InclusionRewriter::Elif(SourceLocation Loc, SourceRange ConditionRange, + ConditionValueKind ConditionValue, + SourceLocation IfLoc) { + auto P = IfConditions.insert( + std::make_pair(Loc.getRawEncoding(), ConditionValue == CVK_True)); + (void)P; + assert(P.second && "Unexpected revisitation of the same elif directive"); +} + /// Simple lookup for a SourceLocation (specifically one denoting the hash in /// an inclusion directive) in the map of inclusion information, FileChanges. const InclusionRewriter::IncludedFile * @@ -233,6 +254,13 @@ InclusionRewriter::FindEnteredModule(SourceLocation Loc) const { return nullptr; } +bool InclusionRewriter::IsIfAtLocationTrue(SourceLocation Loc) const { + const auto I = IfConditions.find(Loc.getRawEncoding()); + if (I != IfConditions.end()) + return I->second; + return false; +} + /// Detect the likely line ending style of \p FromFile by examining the first /// newline found within it. static StringRef DetectEOL(const MemoryBuffer &FromFile) { @@ -346,80 +374,6 @@ StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex, return StringRef(); } -// Expand __has_include and __has_include_next if possible. If there's no -// definitive answer return false. -bool InclusionRewriter::HandleHasInclude( - FileID FileId, Lexer &RawLex, const DirectoryLookup *Lookup, Token &Tok, - bool &FileExists) { - // Lex the opening paren. - RawLex.LexFromRawLexer(Tok); - if (Tok.isNot(tok::l_paren)) - return false; - - RawLex.LexFromRawLexer(Tok); - - SmallString<128> FilenameBuffer; - StringRef Filename; - // Since the raw lexer doesn't give us angle_literals we have to parse them - // ourselves. - // FIXME: What to do if the file name is a macro? - if (Tok.is(tok::less)) { - RawLex.LexFromRawLexer(Tok); - - FilenameBuffer += '<'; - do { - if (Tok.is(tok::eod)) // Sanity check. - return false; - - if (Tok.is(tok::raw_identifier)) - PP.LookUpIdentifierInfo(Tok); - - // Get the string piece. - SmallVector<char, 128> TmpBuffer; - bool Invalid = false; - StringRef TmpName = PP.getSpelling(Tok, TmpBuffer, &Invalid); - if (Invalid) - return false; - - FilenameBuffer += TmpName; - - RawLex.LexFromRawLexer(Tok); - } while (Tok.isNot(tok::greater)); - - FilenameBuffer += '>'; - Filename = FilenameBuffer; - } else { - if (Tok.isNot(tok::string_literal)) - return false; - - bool Invalid = false; - Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid); - if (Invalid) - return false; - } - - // Lex the closing paren. - RawLex.LexFromRawLexer(Tok); - if (Tok.isNot(tok::r_paren)) - return false; - - // Now ask HeaderInfo if it knows about the header. - // FIXME: Subframeworks aren't handled here. Do we care? - bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename); - const DirectoryLookup *CurDir; - const FileEntry *FileEnt = PP.getSourceManager().getFileEntryForID(FileId); - SmallVector<std::pair<const FileEntry *, const DirectoryEntry *>, 1> - Includers; - Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir())); - // FIXME: Why don't we call PP.LookupFile here? - const FileEntry *File = PP.getHeaderSearchInfo().LookupFile( - Filename, SourceLocation(), isAngled, Lookup, CurDir, Includers, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr); - - FileExists = File != nullptr; - return true; -} - /// Use a raw lexer to analyze \p FileId, incrementally copying parts of it /// and including content of included files recursively. void InclusionRewriter::Process(FileID FileId, @@ -519,53 +473,33 @@ void InclusionRewriter::Process(FileID FileId, case tok::pp_elif: { bool elif = (RawToken.getIdentifierInfo()->getPPKeywordID() == tok::pp_elif); - // Rewrite special builtin macros to avoid pulling in host details. + bool isTrue = IsIfAtLocationTrue(RawToken.getLocation()); + OutputContentUpTo(FromFile, NextToWrite, + SM.getFileOffset(HashToken.getLocation()), + LocalEOL, Line, /*EnsureNewline=*/true); do { - // Walk over the directive. RawLex.LexFromRawLexer(RawToken); - if (RawToken.is(tok::raw_identifier)) - PP.LookUpIdentifierInfo(RawToken); - - if (RawToken.is(tok::identifier)) { - bool HasFile; - SourceLocation Loc = RawToken.getLocation(); - - // Rewrite __has_include(x) - if (RawToken.getIdentifierInfo()->isStr("__has_include")) { - if (!HandleHasInclude(FileId, RawLex, nullptr, RawToken, - HasFile)) - continue; - // Rewrite __has_include_next(x) - } else if (RawToken.getIdentifierInfo()->isStr( - "__has_include_next")) { - if (DirLookup) - ++DirLookup; - - if (!HandleHasInclude(FileId, RawLex, DirLookup, RawToken, - HasFile)) - continue; - } else { - continue; - } - // Replace the macro with (0) or (1), followed by the commented - // out macro for reference. - OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc), - LocalEOL, Line, false); - OS << '(' << (int) HasFile << ")/*"; - OutputContentUpTo(FromFile, NextToWrite, - SM.getFileOffset(RawToken.getLocation()) + - RawToken.getLength(), - LocalEOL, Line, false); - OS << "*/"; - } - } while (RawToken.isNot(tok::eod)); + } while (!RawToken.is(tok::eod) && RawToken.isNot(tok::eof)); + // We need to disable the old condition, but that is tricky. + // Trying to comment it out can easily lead to comment nesting. + // So instead make the condition harmless by making it enclose + // and empty block. Moreover, put it itself inside an #if 0 block + // to disable it from getting evaluated (e.g. __has_include_next + // warns if used from the primary source file). + OS << "#if 0 /* disabled by -frewrite-includes */" << MainEOL; if (elif) { - OutputContentUpTo(FromFile, NextToWrite, - SM.getFileOffset(RawToken.getLocation()) + - RawToken.getLength(), - LocalEOL, Line, /*EnsureNewline=*/ true); - WriteLineInfo(FileName, Line, FileType); + OS << "#if 0" << MainEOL; } + OutputContentUpTo(FromFile, NextToWrite, + SM.getFileOffset(RawToken.getLocation()) + + RawToken.getLength(), + LocalEOL, Line, /*EnsureNewline=*/true); + // Close the empty block and the disabling block. + OS << "#endif" << MainEOL; + OS << "#endif /* disabled by -frewrite-includes */" << MainEOL; + OS << (elif ? "#elif " : "#if ") << (isTrue ? "1" : "0") + << " /* evaluated by -frewrite-includes */" << MainEOL; + WriteLineInfo(FileName, Line, FileType); break; } case tok::pp_endif: |