LibCpp: Add "ignore invalid statements" option to Preprocessor

When we run the Preprocessor from the CppComprehensionEngine of
the language server, we don't want the preprocessor to crash if it
encounters an invalid preprocessor statement (for example, an #endif
statement without an accompanying previous #if statement).

To achieve this, this commit adds an "ignore_invalid_statements" flag
to the preprocessor which is set by the CppComprehensionEngine.

Fixes #11064.
This commit is contained in:
Itamar 2021-12-03 10:10:16 +02:00 committed by Andreas Kling
parent 408f05bbb9
commit c3c2fe153b
3 changed files with 9 additions and 0 deletions

View file

@ -574,6 +574,7 @@ OwnPtr<CppComprehensionEngine::DocumentData> CppComprehensionEngine::create_docu
document_data->m_text = move(text);
document_data->m_preprocessor = make<Preprocessor>(document_data->m_filename, document_data->text());
document_data->preprocessor().set_ignore_unsupported_keywords(true);
document_data->preprocessor().set_ignore_invalid_statements(true);
document_data->preprocessor().set_keep_include_statements(true);
document_data->preprocessor().definitions_in_header_callback = [this](StringView include_path) -> Preprocessor::Definitions {

View file

@ -117,6 +117,8 @@ void Preprocessor::handle_preprocessor_keyword(StringView keyword, GenericLexer&
}
if (keyword == "else") {
if (m_options.ignore_invalid_statements && m_current_depth == 0)
return;
VERIFY(m_current_depth > 0);
if (m_depths_of_not_taken_branches.contains_slow(m_current_depth - 1)) {
m_depths_of_not_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth - 1; });
@ -129,6 +131,8 @@ void Preprocessor::handle_preprocessor_keyword(StringView keyword, GenericLexer&
}
if (keyword == "endif") {
if (m_options.ignore_invalid_statements && m_current_depth == 0)
return;
VERIFY(m_current_depth > 0);
--m_current_depth;
if (m_depths_of_not_taken_branches.contains_slow(m_current_depth)) {
@ -198,6 +202,8 @@ void Preprocessor::handle_preprocessor_keyword(StringView keyword, GenericLexer&
}
if (keyword == "elif") {
if (m_options.ignore_invalid_statements && m_current_depth == 0)
return;
VERIFY(m_current_depth > 0);
// FIXME: Evaluate the elif expression
// We currently always treat the expression in #elif as true.

View file

@ -44,6 +44,7 @@ public:
Vector<Substitution> const& substitutions() const { return m_substitutions; }
void set_ignore_unsupported_keywords(bool ignore) { m_options.ignore_unsupported_keywords = ignore; }
void set_ignore_invalid_statements(bool ignore) { m_options.ignore_invalid_statements = ignore; }
void set_keep_include_statements(bool keep) { m_options.keep_include_statements = keep; }
Function<Definitions(StringView)> definitions_in_header_callback { nullptr };
@ -91,6 +92,7 @@ private:
struct Options {
bool ignore_unsupported_keywords { false };
bool ignore_invalid_statements { false };
bool keep_include_statements { false };
} m_options;
};