From c3c2fe153b0910809ff9aaf2be696cd92a270915 Mon Sep 17 00:00:00 2001 From: Itamar Date: Fri, 3 Dec 2021 10:10:16 +0200 Subject: [PATCH] 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. --- .../LanguageServers/Cpp/CppComprehensionEngine.cpp | 1 + Userland/Libraries/LibCpp/Preprocessor.cpp | 6 ++++++ Userland/Libraries/LibCpp/Preprocessor.h | 2 ++ 3 files changed, 9 insertions(+) diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp index d5eefe2914..bcd3dc9b68 100644 --- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp +++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp @@ -574,6 +574,7 @@ OwnPtr CppComprehensionEngine::create_docu document_data->m_text = move(text); document_data->m_preprocessor = make(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 { diff --git a/Userland/Libraries/LibCpp/Preprocessor.cpp b/Userland/Libraries/LibCpp/Preprocessor.cpp index 08f68b48fe..9cf3cd82fb 100644 --- a/Userland/Libraries/LibCpp/Preprocessor.cpp +++ b/Userland/Libraries/LibCpp/Preprocessor.cpp @@ -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. diff --git a/Userland/Libraries/LibCpp/Preprocessor.h b/Userland/Libraries/LibCpp/Preprocessor.h index d5fc287dbb..f834ba918b 100644 --- a/Userland/Libraries/LibCpp/Preprocessor.h +++ b/Userland/Libraries/LibCpp/Preprocessor.h @@ -44,6 +44,7 @@ public: Vector 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_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; };