Skip to content

Commit

Permalink
Lex: add a callback for #pragma mark
Browse files Browse the repository at this point in the history
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
  • Loading branch information
compnerd committed Jul 2, 2021
1 parent a5c3f10 commit 24f4c3e
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 4 deletions.
4 changes: 4 additions & 0 deletions clang/include/clang/Lex/PPCallbacks.h
Expand Up @@ -191,6 +191,10 @@ class PPCallbacks {
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,
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Lex/Preprocessor.h
Expand Up @@ -2365,7 +2365,7 @@ class Preprocessor {

public:
void HandlePragmaOnce(Token &OnceTok);
void HandlePragmaMark();
void HandlePragmaMark(Token &MarkTok);
void HandlePragmaPoison();
void HandlePragmaSystemHeader(Token &SysHeaderTok);
void HandlePragmaDependency(Token &DependencyTok);
Expand Down
10 changes: 7 additions & 3 deletions clang/lib/Lex/Pragma.cpp
Expand Up @@ -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'.
Expand Down Expand Up @@ -992,7 +996,7 @@ struct PragmaMarkHandler : public PragmaHandler {

void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
Token &MarkTok) override {
PP.HandlePragmaMark();
PP.HandlePragmaMark(MarkTok);
}
};

Expand Down
62 changes: 62 additions & 0 deletions clang/unittests/Lex/PPCallbacksTest.cpp
Expand Up @@ -112,6 +112,20 @@ class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
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:
Expand Down Expand Up @@ -256,6 +270,36 @@ class PPCallbacksTest : public ::testing::Test {
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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 24f4c3e

Please sign in to comment.