Lex: add a callback for `#pragma mark`

Allow a preprocessor observer to be notified of mark pragmas.  Although
this does not impact code generation in any way, it is useful for other
clients, such as clangd, to be able to identify any marked regions.

Reviewed By: dgoldman

Differential Revision: https://reviews.llvm.org/D105368
This commit is contained in:
Saleem Abdulrasool 2021-07-02 19:43:01 +00:00 committed by Saleem Abdulrasool
parent a5c3f10b75
commit 24f4c3ebef
4 changed files with 74 additions and 4 deletions

View File

@ -191,6 +191,10 @@ public:
StringRef Str) {
}
/// Callback invoked when a \#pragma mark comment is read.
virtual void PragmaMark(SourceLocation Loc, StringRef Trivia) {
}
/// Callback invoked when a \#pragma detect_mismatch directive is
/// read.
virtual void PragmaDetectMismatch(SourceLocation Loc, StringRef Name,

View File

@ -2365,7 +2365,7 @@ private:
public:
void HandlePragmaOnce(Token &OnceTok);
void HandlePragmaMark();
void HandlePragmaMark(Token &MarkTok);
void HandlePragmaPoison();
void HandlePragmaSystemHeader(Token &SysHeaderTok);
void HandlePragmaDependency(Token &DependencyTok);

View File

@ -412,9 +412,13 @@ void Preprocessor::HandlePragmaOnce(Token &OnceTok) {
HeaderInfo.MarkFileIncludeOnce(getCurrentFileLexer()->getFileEntry());
}
void Preprocessor::HandlePragmaMark() {
void Preprocessor::HandlePragmaMark(Token &MarkTok) {
assert(CurPPLexer && "No current lexer?");
CurLexer->ReadToEndOfLine();
SmallString<64> Buffer;
CurLexer->ReadToEndOfLine(&Buffer);
if (Callbacks)
Callbacks->PragmaMark(MarkTok.getLocation(), Buffer);
}
/// HandlePragmaPoison - Handle \#pragma GCC poison. PoisonTok is the 'poison'.
@ -992,7 +996,7 @@ struct PragmaMarkHandler : public PragmaHandler {
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
Token &MarkTok) override {
PP.HandlePragmaMark();
PP.HandlePragmaMark(MarkTok);
}
};

View File

@ -112,6 +112,20 @@ public:
unsigned State;
};
class PragmaMarkCallbacks : public PPCallbacks {
public:
struct Mark {
SourceLocation Location;
std::string Trivia;
};
std::vector<Mark> Marks;
void PragmaMark(SourceLocation Loc, StringRef Trivia) override {
Marks.emplace_back(Mark{Loc, Trivia.str()});
}
};
// PPCallbacks test fixture.
class PPCallbacksTest : public ::testing::Test {
protected:
@ -256,6 +270,36 @@ protected:
return Callbacks->Results;
}
std::vector<PragmaMarkCallbacks::Mark>
PragmaMarkCall(const char *SourceText) {
std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
llvm::MemoryBuffer::getMemBuffer(SourceText, "test.c");
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
TrivialModuleLoader ModLoader;
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
SourceMgr, HeaderInfo, ModLoader, /*IILookup=*/nullptr,
/*OwnsHeaderSearch=*/false);
PP.Initialize(*Target);
auto *Callbacks = new PragmaMarkCallbacks;
PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
// Lex source text.
PP.EnterMainSourceFile();
while (true) {
Token Tok;
PP.Lex(Tok);
if (Tok.is(tok::eof))
break;
}
return Callbacks->Marks;
}
PragmaOpenCLExtensionCallbacks::CallbackParameters
PragmaOpenCLExtensionCall(const char *SourceText) {
LangOptions OpenCLLangOpts;
@ -424,6 +468,24 @@ TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
ASSERT_EQ(ExpectedState, Parameters.State);
}
TEST_F(PPCallbacksTest, CollectMarks) {
const char *Source =
"#pragma mark\n"
"#pragma mark\r\n"
"#pragma mark - trivia\n"
"#pragma mark - trivia\r\n";
auto Marks = PragmaMarkCall(Source);
ASSERT_EQ(4u, Marks.size());
ASSERT_TRUE(Marks[0].Trivia.empty());
ASSERT_TRUE(Marks[1].Trivia.empty());
ASSERT_FALSE(Marks[2].Trivia.empty());
ASSERT_FALSE(Marks[3].Trivia.empty());
ASSERT_EQ(" - trivia", Marks[2].Trivia);
ASSERT_EQ(" - trivia", Marks[3].Trivia);
}
TEST_F(PPCallbacksTest, DirectiveExprRanges) {
const auto &Results1 = DirectiveExprRange("#if FLUZZY_FLOOF\n#endif\n");
EXPECT_EQ(Results1.size(), 1U);