Преглед изворни кода

AK+Everywhere: Remove the null state of DeprecatedString

This commit removes DeprecatedString's "null" state, and replaces all
its users with one of the following:
- A normal, empty DeprecatedString
- Optional<DeprecatedString>

Note that null states of DeprecatedFlyString/StringView/etc are *not*
affected by this commit. However, DeprecatedString::empty() is now
considered equal to a null StringView.
Ali Mohammad Pur пре 1 година
родитељ
комит
aeee98b3a1
100 измењених фајлова са 339 додато и 404 уклоњено
  1. 1 3
      AK/DeprecatedFlyString.cpp
  2. 9 15
      AK/DeprecatedString.cpp
  3. 18 37
      AK/DeprecatedString.h
  4. 1 1
      AK/GenericLexer.cpp
  5. 1 1
      AK/GenericLexer.h
  6. 0 2
      AK/JsonParser.cpp
  7. 3 7
      AK/JsonValue.cpp
  8. 0 3
      AK/LexicalPath.cpp
  9. 1 11
      AK/StringImpl.cpp
  10. 2 2
      AK/StringView.cpp
  11. 4 8
      AK/URL.cpp
  12. 1 1
      Meta/Lagom/Tools/CodeGenerators/IPCCompiler/main.cpp
  13. 4 4
      Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp
  14. 2 2
      Meta/Lagom/Tools/IPCMagicLinter/main.cpp
  15. 1 1
      Tests/AK/TestCircularDeque.cpp
  16. 3 7
      Tests/AK/TestDeprecatedString.cpp
  17. 1 1
      Tests/AK/TestHashMap.cpp
  18. 1 1
      Tests/AK/TestHashTable.cpp
  19. 0 4
      Tests/AK/TestJSON.cpp
  20. 0 2
      Tests/AK/TestVector.cpp
  21. 1 1
      Tests/LibC/TestRealpath.cpp
  22. 15 12
      Tests/LibJS/test262-runner.cpp
  23. 1 1
      Userland/Applications/DisplaySettings/MonitorSettingsWidget.cpp
  24. 3 3
      Userland/Applications/Mail/MailWidget.cpp
  25. 1 1
      Userland/Applications/NetworkSettings/main.cpp
  26. 1 1
      Userland/Applications/SoundPlayer/M3UParser.cpp
  27. 0 3
      Userland/Applications/SoundPlayer/Player.cpp
  28. 1 1
      Userland/Applications/Spreadsheet/SpreadsheetView.cpp
  29. 1 1
      Userland/Applications/SystemMonitor/MemoryStatsWidget.cpp
  30. 1 1
      Userland/Applications/TextEditor/MainWidget.cpp
  31. 1 1
      Userland/DevTools/HackStudio/Debugger/BacktraceModel.cpp
  32. 1 1
      Userland/DevTools/HackStudio/Debugger/Debugger.cpp
  33. 1 1
      Userland/DevTools/HackStudio/EditorWrapper.cpp
  34. 16 16
      Userland/DevTools/HackStudio/Git/GitRepo.cpp
  35. 2 2
      Userland/DevTools/HackStudio/Git/GitRepo.h
  36. 4 4
      Userland/DevTools/HackStudio/HackStudioWidget.cpp
  37. 2 2
      Userland/DevTools/HackStudio/LanguageServers/FileDB.cpp
  38. 1 1
      Userland/DevTools/HackStudio/LanguageServers/FileDB.h
  39. 1 1
      Userland/DevTools/HackStudio/Locator.cpp
  40. 3 3
      Userland/Libraries/LibC/unistd.cpp
  41. 3 3
      Userland/Libraries/LibCodeComprehension/Cpp/CppComprehensionEngine.cpp
  42. 2 2
      Userland/Libraries/LibCodeComprehension/Cpp/Tests.cpp
  43. 2 2
      Userland/Libraries/LibCodeComprehension/FileDB.cpp
  44. 9 3
      Userland/Libraries/LibCodeComprehension/FileDB.h
  45. 13 11
      Userland/Libraries/LibCore/Account.cpp
  46. 4 4
      Userland/Libraries/LibCore/Account.h
  47. 3 4
      Userland/Libraries/LibCore/ConfigFile.cpp
  48. 7 3
      Userland/Libraries/LibCore/ConfigFile.h
  49. 18 7
      Userland/Libraries/LibCore/System.cpp
  50. 1 1
      Userland/Libraries/LibCore/SystemServerTakeover.cpp
  51. 2 2
      Userland/Libraries/LibCpp/Preprocessor.cpp
  52. 1 1
      Userland/Libraries/LibDNS/Packet.cpp
  53. 1 1
      Userland/Libraries/LibDebug/DebugInfo.cpp
  54. 1 1
      Userland/Libraries/LibELF/Image.cpp
  55. 1 1
      Userland/Libraries/LibFileSystemAccessClient/Client.cpp
  56. 13 10
      Userland/Libraries/LibGUI/AbstractView.cpp
  57. 1 1
      Userland/Libraries/LibGUI/AbstractView.h
  58. 8 18
      Userland/Libraries/LibGUI/FilePicker.cpp
  59. 2 2
      Userland/Libraries/LibGUI/FilePicker.h
  60. 3 3
      Userland/Libraries/LibGUI/FileSystemModel.cpp
  61. 4 1
      Userland/Libraries/LibGUI/ModelEditingDelegate.h
  62. 2 2
      Userland/Libraries/LibGUI/TableView.cpp
  63. 0 1
      Userland/Libraries/LibGUI/Variant.h
  64. 1 1
      Userland/Libraries/LibGemini/Line.cpp
  65. 0 14
      Userland/Libraries/LibHTTP/Job.cpp
  66. 14 14
      Userland/Libraries/LibJS/Runtime/JSONObject.cpp
  67. 2 2
      Userland/Libraries/LibJS/Runtime/JSONObject.h
  68. 1 1
      Userland/Libraries/LibJS/Runtime/PrimitiveString.cpp
  69. 1 1
      Userland/Libraries/LibJS/Runtime/VM.cpp
  70. 3 3
      Userland/Libraries/LibJS/Token.cpp
  71. 0 2
      Userland/Libraries/LibPDF/Parser.cpp
  72. 3 3
      Userland/Libraries/LibSQL/AST/AST.h
  73. 7 7
      Userland/Libraries/LibSQL/AST/Parser.cpp
  74. 1 1
      Userland/Libraries/LibSQL/AST/Parser.h
  75. 2 2
      Userland/Libraries/LibTLS/Handshake.cpp
  76. 4 3
      Userland/Libraries/LibTest/JavaScriptTestRunner.h
  77. 1 1
      Userland/Libraries/LibVT/Attribute.h
  78. 7 7
      Userland/Libraries/LibVT/TerminalWidget.cpp
  79. 2 2
      Userland/Libraries/LibVT/TerminalWidget.h
  80. 1 1
      Userland/Libraries/LibWeb/CSS/CSSNamespaceRule.cpp
  81. 5 5
      Userland/Libraries/LibWeb/CSS/CSSStyleRule.cpp
  82. 3 3
      Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
  83. 3 3
      Userland/Libraries/LibWeb/DOM/Attr.cpp
  84. 1 1
      Userland/Libraries/LibWeb/DOM/Attr.h
  85. 15 13
      Userland/Libraries/LibWeb/DOM/Element.cpp
  86. 3 3
      Userland/Libraries/LibWeb/DOM/Element.h
  87. 8 16
      Userland/Libraries/LibWeb/DOM/Node.cpp
  88. 1 1
      Userland/Libraries/LibWeb/DOM/Node.h
  89. 6 9
      Userland/Libraries/LibWeb/DOM/StyleElementUtils.cpp
  90. 1 1
      Userland/Libraries/LibWeb/DOM/StyleElementUtils.h
  91. 8 6
      Userland/Libraries/LibWeb/DOMParsing/XMLSerializer.cpp
  92. 1 1
      Userland/Libraries/LibWeb/Dump.cpp
  93. 4 4
      Userland/Libraries/LibWeb/HTML/HTMLAnchorElement.cpp
  94. 2 2
      Userland/Libraries/LibWeb/HTML/HTMLAnchorElement.h
  95. 4 4
      Userland/Libraries/LibWeb/HTML/HTMLAreaElement.cpp
  96. 2 2
      Userland/Libraries/LibWeb/HTML/HTMLAreaElement.h
  97. 1 1
      Userland/Libraries/LibWeb/HTML/HTMLBaseElement.cpp
  98. 1 1
      Userland/Libraries/LibWeb/HTML/HTMLBaseElement.h
  99. 8 8
      Userland/Libraries/LibWeb/HTML/HTMLBodyElement.cpp
  100. 1 1
      Userland/Libraries/LibWeb/HTML/HTMLBodyElement.h

+ 1 - 3
AK/DeprecatedFlyString.cpp

@@ -38,8 +38,6 @@ void DeprecatedFlyString::did_destroy_impl(Badge<StringImpl>, StringImpl& impl)
 
 DeprecatedFlyString::DeprecatedFlyString(DeprecatedString const& string)
 {
-    if (string.is_null())
-        return;
     if (string.impl()->is_fly()) {
         m_impl = string.impl();
         return;
@@ -60,7 +58,7 @@ DeprecatedFlyString::DeprecatedFlyString(StringView string)
     if (string.is_null())
         return;
     auto it = fly_impls().find(string.hash(), [&](auto& candidate) {
-        return string == candidate;
+        return string == *candidate;
     });
     if (it == fly_impls().end()) {
         auto new_string = string.to_deprecated_string();

+ 9 - 15
AK/DeprecatedString.cpp

@@ -28,6 +28,9 @@ bool DeprecatedString::operator==(DeprecatedString const& other) const
 
 bool DeprecatedString::operator==(StringView other) const
 {
+    if (other.is_null())
+        return is_empty();
+
     return view() == other;
 }
 
@@ -55,9 +58,7 @@ bool DeprecatedString::copy_characters_to_buffer(char* buffer, size_t buffer_siz
 
 DeprecatedString DeprecatedString::isolated_copy() const
 {
-    if (!m_impl)
-        return {};
-    if (!m_impl->length())
+    if (m_impl->length() == 0)
         return empty();
     char* buffer;
     auto impl = StringImpl::create_uninitialized(length(), buffer);
@@ -69,7 +70,6 @@ DeprecatedString DeprecatedString::substring(size_t start, size_t length) const
 {
     if (!length)
         return DeprecatedString::empty();
-    VERIFY(m_impl);
     VERIFY(!Checked<size_t>::addition_would_overflow(start, length));
     VERIFY(start + length <= m_impl->length());
     return { characters() + start, length };
@@ -77,14 +77,12 @@ DeprecatedString DeprecatedString::substring(size_t start, size_t length) const
 
 DeprecatedString DeprecatedString::substring(size_t start) const
 {
-    VERIFY(m_impl);
     VERIFY(start <= length());
     return { characters() + start, length() - start };
 }
 
 StringView DeprecatedString::substring_view(size_t start, size_t length) const
 {
-    VERIFY(m_impl);
     VERIFY(!Checked<size_t>::addition_would_overflow(start, length));
     VERIFY(start + length <= m_impl->length());
     return { characters() + start, length };
@@ -92,7 +90,6 @@ StringView DeprecatedString::substring_view(size_t start, size_t length) const
 
 StringView DeprecatedString::substring_view(size_t start) const
 {
-    VERIFY(m_impl);
     VERIFY(start <= length());
     return { characters() + start, length() - start };
 }
@@ -157,8 +154,6 @@ Vector<StringView> DeprecatedString::split_view(char const separator, SplitBehav
 
 ByteBuffer DeprecatedString::to_byte_buffer() const
 {
-    if (!m_impl)
-        return {};
     // FIXME: Handle OOM failure.
     return ByteBuffer::copy(bytes()).release_value_but_fixme_should_propagate_errors();
 }
@@ -379,21 +374,17 @@ DeprecatedString escape_html_entities(StringView html)
 }
 
 DeprecatedString::DeprecatedString(DeprecatedFlyString const& string)
-    : m_impl(string.impl())
+    : m_impl(*string.impl())
 {
 }
 
 DeprecatedString DeprecatedString::to_lowercase() const
 {
-    if (!m_impl)
-        return {};
     return m_impl->to_lowercase();
 }
 
 DeprecatedString DeprecatedString::to_uppercase() const
 {
-    if (!m_impl)
-        return {};
     return m_impl->to_uppercase();
 }
 
@@ -414,6 +405,9 @@ DeprecatedString DeprecatedString::invert_case() const
 
 bool DeprecatedString::operator==(char const* cstring) const
 {
+    if (!cstring)
+        return is_empty();
+
     return view() == cstring;
 }
 
@@ -438,7 +432,7 @@ ErrorOr<DeprecatedString> DeprecatedString::from_utf8(ReadonlyBytes bytes)
 {
     if (!Utf8View(bytes).validate())
         return Error::from_string_literal("DeprecatedString::from_utf8: Input was not valid UTF-8");
-    return DeprecatedString { StringImpl::create(bytes) };
+    return DeprecatedString { *StringImpl::create(bytes) };
 }
 
 }

+ 18 - 37
AK/DeprecatedString.h

@@ -40,10 +40,13 @@ class DeprecatedString {
 public:
     ~DeprecatedString() = default;
 
-    DeprecatedString() = default;
+    DeprecatedString()
+        : m_impl(StringImpl::the_empty_stringimpl())
+    {
+    }
 
     DeprecatedString(StringView view)
-        : m_impl(StringImpl::create(view.characters_without_null_termination(), view.length()))
+        : m_impl(*StringImpl::create(view.characters_without_null_termination(), view.length()))
     {
     }
 
@@ -55,20 +58,21 @@ public:
     DeprecatedString(DeprecatedString&& other)
         : m_impl(move(other.m_impl))
     {
+        other.m_impl = StringImpl::the_empty_stringimpl();
     }
 
     DeprecatedString(char const* cstring, ShouldChomp shouldChomp = NoChomp)
-        : m_impl(StringImpl::create(cstring, shouldChomp))
+        : m_impl(*StringImpl::create(cstring, shouldChomp))
     {
     }
 
     DeprecatedString(char const* cstring, size_t length, ShouldChomp shouldChomp = NoChomp)
-        : m_impl(StringImpl::create(cstring, length, shouldChomp))
+        : m_impl(*StringImpl::create(cstring, length, shouldChomp))
     {
     }
 
     explicit DeprecatedString(ReadonlyBytes bytes, ShouldChomp shouldChomp = NoChomp)
-        : m_impl(StringImpl::create(bytes, shouldChomp))
+        : m_impl(*StringImpl::create(bytes, shouldChomp))
     {
     }
 
@@ -77,18 +81,8 @@ public:
     {
     }
 
-    DeprecatedString(StringImpl const* impl)
-        : m_impl(impl)
-    {
-    }
-
-    DeprecatedString(RefPtr<StringImpl const>&& impl)
-        : m_impl(move(impl))
-    {
-    }
-
     DeprecatedString(NonnullRefPtr<StringImpl const>&& impl)
-        : m_impl(move(impl))
+        : m_impl(*move(impl))
     {
     }
 
@@ -174,31 +168,25 @@ public:
     [[nodiscard]] StringView substring_view(size_t start, size_t length) const;
     [[nodiscard]] StringView substring_view(size_t start) const;
 
-    [[nodiscard]] bool is_null() const { return !m_impl; }
     [[nodiscard]] ALWAYS_INLINE bool is_empty() const { return length() == 0; }
-    [[nodiscard]] ALWAYS_INLINE size_t length() const { return m_impl ? m_impl->length() : 0; }
-    // Includes NUL-terminator, if non-nullptr.
-    [[nodiscard]] ALWAYS_INLINE char const* characters() const { return m_impl ? m_impl->characters() : nullptr; }
+    [[nodiscard]] ALWAYS_INLINE size_t length() const { return m_impl->length(); }
+    // Includes NUL-terminator.
+    [[nodiscard]] ALWAYS_INLINE char const* characters() const { return m_impl->characters(); }
 
     [[nodiscard]] bool copy_characters_to_buffer(char* buffer, size_t buffer_size) const;
 
     [[nodiscard]] ALWAYS_INLINE ReadonlyBytes bytes() const
     {
-        if (m_impl) {
-            return m_impl->bytes();
-        }
-        return {};
+        return m_impl->bytes();
     }
 
     [[nodiscard]] ALWAYS_INLINE char const& operator[](size_t i) const
     {
-        VERIFY(!is_null());
         return (*m_impl)[i];
     }
 
     [[nodiscard]] ALWAYS_INLINE u8 byte_at(size_t i) const
     {
-        VERIFY(!is_null());
         return bit_cast<u8>((*m_impl)[i]);
     }
 
@@ -251,22 +239,15 @@ public:
         return *this;
     }
 
-    DeprecatedString& operator=(nullptr_t)
-    {
-        m_impl = nullptr;
-        return *this;
-    }
-
-    DeprecatedString& operator=(ReadonlyBytes bytes)
+    template<OneOf<ReadonlyBytes, Bytes> T>
+    DeprecatedString& operator=(T bytes)
     {
-        m_impl = StringImpl::create(bytes);
+        m_impl = *StringImpl::create(bytes);
         return *this;
     }
 
     [[nodiscard]] u32 hash() const
     {
-        if (!m_impl)
-            return 0;
         return m_impl->hash();
     }
 
@@ -323,7 +304,7 @@ public:
     }
 
 private:
-    RefPtr<StringImpl const> m_impl;
+    NonnullRefPtr<StringImpl const> m_impl;
 };
 
 template<>

+ 1 - 1
AK/GenericLexer.cpp

@@ -129,7 +129,7 @@ StringView GenericLexer::consume_quoted_string(char escape_char)
 }
 
 #ifndef KERNEL
-DeprecatedString GenericLexer::consume_and_unescape_string(char escape_char)
+Optional<DeprecatedString> GenericLexer::consume_and_unescape_string(char escape_char)
 {
     auto view = consume_quoted_string(escape_char);
     if (view.is_null())

+ 1 - 1
AK/GenericLexer.h

@@ -119,7 +119,7 @@ public:
     StringView consume_until(StringView);
     StringView consume_quoted_string(char escape_char = 0);
 #ifndef KERNEL
-    DeprecatedString consume_and_unescape_string(char escape_char = '\\');
+    Optional<DeprecatedString> consume_and_unescape_string(char escape_char = '\\');
 #endif
 
     enum class UnicodeEscapeError {

+ 0 - 2
AK/JsonParser.cpp

@@ -132,8 +132,6 @@ ErrorOr<JsonValue> JsonParser::parse_object()
             break;
         ignore_while(is_space);
         auto name = TRY(consume_and_unescape_string());
-        if (name.is_null())
-            return Error::from_string_literal("JsonParser: Expected object property name");
         ignore_while(is_space);
         if (!consume_specific(':'))
             return Error::from_string_literal("JsonParser: Expected ':'");

+ 3 - 7
AK/JsonValue.cpp

@@ -174,13 +174,9 @@ JsonValue::JsonValue(double value)
 
 JsonValue::JsonValue(DeprecatedString const& value)
 {
-    if (value.is_null()) {
-        m_type = Type::Null;
-    } else {
-        m_type = Type::String;
-        m_value.as_string = const_cast<StringImpl*>(value.impl());
-        m_value.as_string->ref();
-    }
+    m_type = Type::String;
+    m_value.as_string = const_cast<StringImpl*>(value.impl());
+    m_value.as_string->ref();
 }
 
 JsonValue::JsonValue(StringView value)

+ 0 - 3
AK/LexicalPath.cpp

@@ -90,9 +90,6 @@ bool LexicalPath::is_child_of(LexicalPath const& possible_parent) const
 
 DeprecatedString LexicalPath::canonicalized_path(DeprecatedString path)
 {
-    if (path.is_null())
-        return {};
-
     // NOTE: We never allow an empty m_string, if it's empty, we just set it to '.'.
     if (path.is_empty())
         return ".";

+ 1 - 11
AK/StringImpl.cpp

@@ -47,9 +47,6 @@ NonnullRefPtr<StringImpl const> StringImpl::create_uninitialized(size_t length,
 
 RefPtr<StringImpl const> StringImpl::create(char const* cstring, size_t length, ShouldChomp should_chomp)
 {
-    if (!cstring)
-        return nullptr;
-
     if (should_chomp) {
         while (length) {
             char last_ch = cstring[length - 1];
@@ -72,10 +69,7 @@ RefPtr<StringImpl const> StringImpl::create(char const* cstring, size_t length,
 
 RefPtr<StringImpl const> StringImpl::create(char const* cstring, ShouldChomp shouldChomp)
 {
-    if (!cstring)
-        return nullptr;
-
-    if (!*cstring)
+    if (!cstring || !*cstring)
         return the_empty_stringimpl();
 
     return create(cstring, strlen(cstring), shouldChomp);
@@ -88,8 +82,6 @@ RefPtr<StringImpl const> StringImpl::create(ReadonlyBytes bytes, ShouldChomp sho
 
 RefPtr<StringImpl const> StringImpl::create_lowercased(char const* cstring, size_t length)
 {
-    if (!cstring)
-        return nullptr;
     if (!length)
         return the_empty_stringimpl();
     char* buffer;
@@ -101,8 +93,6 @@ RefPtr<StringImpl const> StringImpl::create_lowercased(char const* cstring, size
 
 RefPtr<StringImpl const> StringImpl::create_uppercased(char const* cstring, size_t length)
 {
-    if (!cstring)
-        return nullptr;
     if (!length)
         return the_empty_stringimpl();
     char* buffer;

+ 2 - 2
AK/StringView.cpp

@@ -178,12 +178,12 @@ bool StringView::equals_ignoring_ascii_case(StringView other) const
 #ifndef KERNEL
 DeprecatedString StringView::to_lowercase_string() const
 {
-    return StringImpl::create_lowercased(characters_without_null_termination(), length());
+    return StringImpl::create_lowercased(characters_without_null_termination(), length()).release_nonnull();
 }
 
 DeprecatedString StringView::to_uppercase_string() const
 {
-    return StringImpl::create_uppercased(characters_without_null_termination(), length());
+    return StringImpl::create_uppercased(characters_without_null_termination(), length()).release_nonnull();
 }
 
 DeprecatedString StringView::to_titlecase_string() const

+ 4 - 8
AK/URL.cpp

@@ -191,13 +191,11 @@ URL URL::create_with_file_scheme(DeprecatedString const& path, DeprecatedString
 
     URL url;
     url.set_scheme("file"_string);
-    // NOTE: If the hostname is localhost (or null, which implies localhost), it should be set to the empty string.
-    //       This is because a file URL always needs a non-null hostname.
-    url.set_host(hostname.is_null() || hostname == "localhost" ? String {} : String::from_deprecated_string(hostname).release_value_but_fixme_should_propagate_errors());
+    url.set_host(hostname == "localhost" ? String {} : String::from_deprecated_string(hostname).release_value_but_fixme_should_propagate_errors());
     url.set_paths(lexical_path.parts());
     if (path.ends_with('/'))
         url.append_slash();
-    if (!fragment.is_null())
+    if (!fragment.is_empty())
         url.set_fragment(String::from_deprecated_string(fragment).release_value_but_fixme_should_propagate_errors());
     return url;
 }
@@ -208,14 +206,12 @@ URL URL::create_with_help_scheme(DeprecatedString const& path, DeprecatedString
 
     URL url;
     url.set_scheme("help"_string);
-    // NOTE: If the hostname is localhost (or null, which implies localhost), it should be set to the empty string.
-    //       This is because a file URL always needs a non-null hostname.
-    url.set_host(hostname.is_null() || hostname == "localhost" ? String {} : String::from_deprecated_string(hostname).release_value_but_fixme_should_propagate_errors());
+    url.set_host(hostname == "localhost" ? String {} : String::from_deprecated_string(hostname).release_value_but_fixme_should_propagate_errors());
 
     url.set_paths(lexical_path.parts());
     if (path.ends_with('/'))
         url.append_slash();
-    if (!fragment.is_null())
+    if (!fragment.is_empty())
         url.set_fragment(String::from_deprecated_string(fragment).release_value_but_fixme_should_propagate_errors());
     return url;
 }

+ 1 - 1
Meta/Lagom/Tools/CodeGenerators/IPCCompiler/main.cpp

@@ -311,7 +311,7 @@ void do_message(SourceGenerator message_generator, DeprecatedString const& name,
 class @message.pascal_name@ final : public IPC::Message {
 public:)~~~");
 
-    if (!response_type.is_null())
+    if (!response_type.is_empty())
         message_generator.appendln(R"~~~(
    typedef class @message.response_type@ ResponseType;)~~~");
 

+ 4 - 4
Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp

@@ -785,7 +785,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
                 }
                 i++;
             }
-            if (current_dictionary->parent_name.is_null())
+            if (current_dictionary->parent_name.is_empty())
                 break;
             VERIFY(interface.dictionaries.contains(current_dictionary->parent_name));
             current_dictionary = &interface.dictionaries.find(current_dictionary->parent_name)->value;
@@ -1755,7 +1755,7 @@ static void generate_wrap_statement(SourceGenerator& generator, DeprecatedString
 )~~~");
             }
 
-            if (current_dictionary->parent_name.is_null())
+            if (current_dictionary->parent_name.is_empty())
                 break;
             VERIFY(interface.dictionaries.contains(current_dictionary->parent_name));
             current_dictionary = &interface.dictionaries.find(current_dictionary->parent_name)->value;
@@ -2352,7 +2352,7 @@ static void collect_attribute_values_of_an_inheritance_stack(SourceGenerator& fu
 
             if (attribute.extended_attributes.contains("Reflect")) {
                 auto attribute_name = attribute.extended_attributes.get("Reflect").value();
-                if (attribute_name.is_null())
+                if (attribute_name.is_empty())
                     attribute_name = attribute.name;
                 attribute_name = make_input_acceptable_cpp(attribute_name);
 
@@ -2837,7 +2837,7 @@ static JS::ThrowCompletionOr<@fully_qualified_name@*> impl_from(JS::VM& vm)
 
         if (attribute.extended_attributes.contains("Reflect")) {
             auto attribute_name = attribute.extended_attributes.get("Reflect").value();
-            if (attribute_name.is_null())
+            if (attribute_name.is_empty())
                 attribute_name = attribute.name;
             attribute_name = make_input_acceptable_cpp(attribute_name);
 

+ 2 - 2
Meta/Lagom/Tools/IPCMagicLinter/main.cpp

@@ -52,7 +52,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
                 if (!line.starts_with("endpoint "sv))
                     continue;
                 auto line_endpoint_name = line.substring_view("endpoint "sv.length());
-                if (!endpoint_name.is_null()) {
+                if (!endpoint_name.is_empty()) {
                     // Note: If there are three or more endpoints defined in a file, these errors will look a bit wonky.
                     // However, that's fine, because it shouldn't happen in the first place.
                     warnln("Error: Multiple endpoints in file '{}': Found {} and {}", filename, endpoint_name, line_endpoint_name);
@@ -72,7 +72,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
             had_errors = true;
             continue; // next file
         }
-        if (endpoint_name.is_null()) {
+        if (endpoint_name.is_empty()) {
             // If this happens, this file probably needs to parse the endpoint name more carefully.
             warnln("Error: Could not detect endpoint name in file '{}'", filename);
             had_errors = true;

+ 1 - 1
Tests/AK/TestCircularDeque.cpp

@@ -41,7 +41,7 @@ TEST_CASE(enqueue_begin_being_moved_from)
 
     DeprecatedString str { "test" };
     strings.enqueue_begin(move(str));
-    EXPECT(str.is_null());
+    EXPECT(str.is_empty());
 }
 
 TEST_CASE(deque_end)

+ 3 - 7
Tests/AK/TestDeprecatedString.cpp

@@ -14,11 +14,9 @@
 
 TEST_CASE(construct_empty)
 {
-    EXPECT(DeprecatedString().is_null());
     EXPECT(DeprecatedString().is_empty());
-    EXPECT(!DeprecatedString().characters());
+    EXPECT(DeprecatedString().characters() != nullptr);
 
-    EXPECT(!DeprecatedString("").is_null());
     EXPECT(DeprecatedString("").is_empty());
     EXPECT(DeprecatedString("").characters() != nullptr);
 
@@ -29,7 +27,6 @@ TEST_CASE(construct_contents)
 {
     DeprecatedString test_string = "ABCDEF";
     EXPECT(!test_string.is_empty());
-    EXPECT(!test_string.is_null());
     EXPECT_EQ(test_string.length(), 6u);
     EXPECT_EQ(test_string.length(), strlen(test_string.characters()));
     EXPECT(test_string.characters() != nullptr);
@@ -42,7 +39,7 @@ TEST_CASE(construct_contents)
 
 TEST_CASE(equal)
 {
-    EXPECT_NE(DeprecatedString::empty(), DeprecatedString {});
+    EXPECT_EQ(DeprecatedString::empty(), DeprecatedString {});
 }
 
 TEST_CASE(compare)
@@ -116,7 +113,7 @@ TEST_CASE(move_string)
     auto test_string_copy = test_string;
     auto test_string_move = move(test_string_copy);
     EXPECT_EQ(test_string, test_string_move);
-    EXPECT(test_string_copy.is_null());
+    EXPECT(test_string_copy.is_empty());
 }
 
 TEST_CASE(repeated)
@@ -253,7 +250,6 @@ TEST_CASE(builder_zero_initial_capacity)
     StringBuilder builder(0);
     builder.append(""sv);
     auto built = builder.to_deprecated_string();
-    EXPECT_EQ(built.is_null(), false);
     EXPECT_EQ(built.length(), 0u);
 }
 

+ 1 - 1
Tests/AK/TestHashMap.cpp

@@ -49,7 +49,7 @@ TEST_CASE(range_loop)
 
     int loop_counter = 0;
     for (auto& it : number_to_string) {
-        EXPECT_EQ(it.value.is_null(), false);
+        EXPECT_EQ(it.value.is_empty(), false);
         ++loop_counter;
     }
     EXPECT_EQ(loop_counter, 3);

+ 1 - 1
Tests/AK/TestHashTable.cpp

@@ -64,7 +64,7 @@ TEST_CASE(range_loop)
 
     int loop_counter = 0;
     for (auto& it : strings) {
-        EXPECT_EQ(it.is_null(), false);
+        EXPECT_EQ(it.is_empty(), false);
         ++loop_counter;
     }
     EXPECT_EQ(loop_counter, 3);

+ 0 - 4
Tests/AK/TestJSON.cpp

@@ -60,7 +60,6 @@ TEST_CASE(json_empty_string)
 {
     auto json = JsonValue::from_string("\"\""sv).value();
     EXPECT_EQ(json.type(), JsonValue::Type::String);
-    EXPECT_EQ(json.as_string().is_null(), false);
     EXPECT_EQ(json.as_string().is_empty(), true);
 }
 
@@ -68,7 +67,6 @@ TEST_CASE(json_string)
 {
     auto json = JsonValue::from_string("\"A\""sv).value();
     EXPECT_EQ(json.type(), JsonValue::Type::String);
-    EXPECT_EQ(json.as_string().is_null(), false);
     EXPECT_EQ(json.as_string().length(), size_t { 1 });
     EXPECT_EQ(json.as_string() == "A", true);
 }
@@ -77,7 +75,6 @@ TEST_CASE(json_utf8_character)
 {
     auto json = JsonValue::from_string("\"\\u0041\""sv).value();
     EXPECT_EQ(json.type(), JsonValue::Type::String);
-    EXPECT_EQ(json.as_string().is_null(), false);
     EXPECT_EQ(json.as_string().length(), size_t { 1 });
     EXPECT_EQ(json.as_string() == "A", true);
 }
@@ -92,7 +89,6 @@ TEST_CASE(json_utf8_multibyte)
 
     auto& json = json_or_error.value();
     EXPECT_EQ(json.type(), JsonValue::Type::String);
-    EXPECT_EQ(json.as_string().is_null(), false);
     EXPECT_EQ(json.as_string().length(), size_t { 2 });
     EXPECT_EQ(json.as_string() == "š", true);
     EXPECT_EQ(json.as_string() == "\xc5\xa1", true);

+ 0 - 2
Tests/AK/TestVector.cpp

@@ -44,14 +44,12 @@ TEST_CASE(strings)
 
     int loop_counter = 0;
     for (DeprecatedString const& string : strings) {
-        EXPECT(!string.is_null());
         EXPECT(!string.is_empty());
         ++loop_counter;
     }
 
     loop_counter = 0;
     for (auto& string : (const_cast<Vector<DeprecatedString> const&>(strings))) {
-        EXPECT(!string.is_null());
         EXPECT(!string.is_empty());
         ++loop_counter;
     }

+ 1 - 1
Tests/LibC/TestRealpath.cpp

@@ -21,7 +21,7 @@ static constexpr char PATH_LOREM_250[] = "This-is-an-annoyingly-long-name-that-s
 
 static constexpr size_t ITERATION_DEPTH = 17;
 
-static void check_result(char const* what, DeprecatedString const& expected, char const* actual)
+static void check_result(char const* what, StringView expected, char const* actual)
 {
     if (expected != actual)
         FAIL(DeprecatedString::formatted("Expected {} to be \"{}\" ({} characters)", what, actual, actual ? strlen(actual) : 0));

+ 15 - 12
Tests/LibJS/test262-runner.cpp

@@ -337,7 +337,7 @@ static Result<TestMetadata, DeprecatedString> extract_metadata(StringView source
                     failed_message = "Failed to find phase in negative attributes";
                     break;
                 }
-                if (metadata.type.is_null()) {
+                if (metadata.type.is_empty()) {
                     failed_message = "Failed to find type in negative attributes";
                     break;
                 }
@@ -640,7 +640,7 @@ int main(int argc, char** argv)
     auto collect_output = [&] {
         fflush(stdout);
         auto nread = read(stdout_pipe[0], buffer, BUFFER_SIZE);
-        DeprecatedString value;
+        Optional<DeprecatedString> value;
 
         if (nread > 0) {
             value = DeprecatedString { buffer, static_cast<size_t>(nread) };
@@ -743,15 +743,16 @@ int main(int argc, char** argv)
             auto result = run_test(original_contents, path, metadata);
             DISARM_TIMER();
 
-            DeprecatedString first_output = collect_output();
-            if (!first_output.is_null())
-                result_object.set("output", first_output);
+            auto first_output = collect_output();
+            if (first_output.has_value())
+                result_object.set("output", *first_output);
 
             passed = verify_test(result, metadata, result_object);
+            auto output = first_output.value_or("");
             if (metadata.is_async && !s_parse_only) {
-                if (!first_output.contains("Test262:AsyncTestComplete"sv) || first_output.contains("Test262:AsyncTestFailure"sv)) {
+                if (!output.contains("Test262:AsyncTestComplete"sv) || output.contains("Test262:AsyncTestFailure"sv)) {
                     result_object.set("async_fail", true);
-                    if (first_output.is_null())
+                    if (!first_output.has_value())
                         result_object.set("output", JsonValue { AK::JsonValue::Type::Null });
 
                     passed = false;
@@ -766,15 +767,17 @@ int main(int argc, char** argv)
             auto result = run_test(with_strict, path, metadata);
             DISARM_TIMER();
 
-            DeprecatedString first_output = collect_output();
-            if (!first_output.is_null())
-                result_object.set("strict_output", first_output);
+            auto first_output = collect_output();
+            if (first_output.has_value())
+                result_object.set("strict_output", *first_output);
 
             passed = verify_test(result, metadata, result_object);
+            auto output = first_output.value_or("");
+
             if (metadata.is_async && !s_parse_only) {
-                if (!first_output.contains("Test262:AsyncTestComplete"sv) || first_output.contains("Test262:AsyncTestFailure"sv)) {
+                if (!output.contains("Test262:AsyncTestComplete"sv) || output.contains("Test262:AsyncTestFailure"sv)) {
                     result_object.set("async_fail", true);
-                    if (first_output.is_null())
+                    if (!first_output.has_value())
                         result_object.set("output", JsonValue { AK::JsonValue::Type::Null });
 
                     passed = false;

+ 1 - 1
Userland/Applications/DisplaySettings/MonitorSettingsWidget.cpp

@@ -141,7 +141,7 @@ static ErrorOr<String> display_name_from_edid(EDID::Parser const& edid)
     auto product_name = edid.display_product_name();
 
     auto build_manufacturer_product_name = [&]() -> ErrorOr<String> {
-        if (product_name.is_null() || product_name.is_empty())
+        if (product_name.is_empty())
             return TRY(String::from_deprecated_string(manufacturer_name));
         return String::formatted("{} {}", manufacturer_name, product_name);
     };

+ 3 - 3
Userland/Applications/Mail/MailWidget.cpp

@@ -319,7 +319,7 @@ void MailWidget::selected_mailbox(GUI::ModelIndex const& index)
         DeprecatedString date = internal_date.to_deprecated_string();
         DeprecatedString subject = envelope.subject.value_or("(No subject)");
         if (subject.contains("=?"sv) && subject.contains("?="sv)) {
-            subject = MUST(IMAP::decode_rfc2047_encoded_words(subject));
+            subject = MUST(IMAP::decode_rfc2047_encoded_words(subject)).span();
         }
 
         StringBuilder sender_builder;
@@ -491,9 +491,9 @@ void MailWidget::selected_email_to_load(GUI::ModelIndex const& index)
     } else if (selected_alternative_encoding.equals_ignoring_ascii_case("base64"sv)) {
         auto decoded_base64 = decode_base64(encoded_data);
         if (!decoded_base64.is_error())
-            decoded_data = decoded_base64.release_value();
+            decoded_data = decoded_base64.release_value().span();
     } else if (selected_alternative_encoding.equals_ignoring_ascii_case("quoted-printable"sv)) {
-        decoded_data = IMAP::decode_quoted_printable(encoded_data).release_value_but_fixme_should_propagate_errors();
+        decoded_data = IMAP::decode_quoted_printable(encoded_data).release_value_but_fixme_should_propagate_errors().span();
     } else {
         dbgln("Mail: Unimplemented decoder for encoding: {}", selected_alternative_encoding);
         GUI::MessageBox::show(window(), DeprecatedString::formatted("The e-mail encoding '{}' is currently unsupported.", selected_alternative_encoding), "Unsupported"sv, GUI::MessageBox::Type::Information);

+ 1 - 1
Userland/Applications/NetworkSettings/main.cpp

@@ -24,7 +24,7 @@ ErrorOr<int> serenity_main(Main::Arguments args)
     TRY(Core::System::unveil("/tmp/portal/window", "rw"));
     TRY(Core::System::unveil(nullptr, nullptr));
 
-    DeprecatedString adapter;
+    StringView adapter;
 
     Core::ArgsParser parser;
     parser.add_positional_argument(adapter, "Adapter to display settings for", "adapter", Core::ArgsParser::Required::No);

+ 1 - 1
Userland/Applications/SoundPlayer/M3UParser.cpp

@@ -26,7 +26,7 @@ NonnullOwnPtr<M3UParser> M3UParser::from_file(StringView path)
 NonnullOwnPtr<M3UParser> M3UParser::from_memory(DeprecatedString const& m3u_contents, bool utf8)
 {
     auto parser = make<M3UParser>();
-    VERIFY(!m3u_contents.is_null() && !m3u_contents.is_empty() && !m3u_contents.is_whitespace());
+    VERIFY(!m3u_contents.is_empty() && !m3u_contents.is_whitespace());
     parser->m_m3u_raw_data = m3u_contents;
     parser->m_use_utf8 = utf8;
     return parser;

+ 0 - 3
Userland/Applications/SoundPlayer/Player.cpp

@@ -40,9 +40,6 @@ Player::Player(Audio::ConnectionToServer& audio_client_connection)
 
 void Player::play_file_path(DeprecatedString const& path)
 {
-    if (path.is_null())
-        return;
-
     if (!FileSystem::exists(path)) {
         audio_load_error(path, "File does not exist"sv);
         return;

+ 1 - 1
Userland/Applications/Spreadsheet/SpreadsheetView.cpp

@@ -22,7 +22,7 @@ namespace Spreadsheet {
 
 void SpreadsheetView::EditingDelegate::set_value(GUI::Variant const& value, GUI::ModelEditingDelegate::SelectionBehavior selection_behavior)
 {
-    if (value.as_string().is_null()) {
+    if (!value.is_valid()) {
         StringModelEditingDelegate::set_value("", selection_behavior);
         commit();
         return;

+ 1 - 1
Userland/Applications/SystemMonitor/MemoryStatsWidget.cpp

@@ -74,7 +74,7 @@ void MemoryStatsWidget::set_graph_widget(GraphWidget& graph)
 void MemoryStatsWidget::set_graph_widget_via_name(DeprecatedString name)
 {
     m_graph_widget_name = move(name);
-    if (!m_graph_widget_name.is_null()) {
+    if (!m_graph_widget_name.is_empty()) {
         // FIXME: We assume here that the graph widget is a sibling or descendant of a sibling. This prevents more complex hierarchies.
         auto* maybe_graph = parent_widget()->find_descendant_of_type_named<GraphWidget>(m_graph_widget_name);
         if (maybe_graph) {

+ 1 - 1
Userland/Applications/TextEditor/MainWidget.cpp

@@ -279,7 +279,7 @@ MainWidget::MainWidget()
 
     m_save_as_action = GUI::CommonActions::make_save_as_action([&](auto&) {
         auto extension = m_extension;
-        if (extension.is_null() && m_editor->syntax_highlighter())
+        if (extension.is_empty() && m_editor->syntax_highlighter())
             extension = Syntax::common_language_extension(m_editor->syntax_highlighter()->language());
 
         auto response = FileSystemAccessClient::Client::the().save_file(window(), m_name, extension);

+ 1 - 1
Userland/DevTools/HackStudio/Debugger/BacktraceModel.cpp

@@ -47,7 +47,7 @@ Vector<BacktraceModel::FrameInfo> BacktraceModel::create_backtrace(Debug::Proces
         if (frame_index > 0)
             --current_instruction;
         DeprecatedString name = lib->debug_info->elf().symbolicate(current_instruction - lib->base_address);
-        if (name.is_null()) {
+        if (name.is_empty()) {
             dbgln("BacktraceModel: couldn't find containing function for address: {:p} (library={})", current_instruction, lib->name);
             name = "<missing>";
         }

+ 1 - 1
Userland/DevTools/HackStudio/Debugger/Debugger.cpp

@@ -134,7 +134,7 @@ void Debugger::start()
 
 Debugger::CreateDebugSessionResult Debugger::create_debug_session()
 {
-    if (!m_executable_path.is_null()) {
+    if (!m_executable_path.is_empty()) {
         auto child_setup_callback = [this]() {
             if (m_child_setup_callback)
                 return m_child_setup_callback();

+ 1 - 1
Userland/DevTools/HackStudio/EditorWrapper.cpp

@@ -113,7 +113,7 @@ void EditorWrapper::set_project_root(DeprecatedString const& project_root)
 void EditorWrapper::update_title()
 {
     StringBuilder title;
-    if (m_filename.is_null())
+    if (m_filename.is_empty())
         title.append(untitled_label);
     else
         title.append(m_filename);

+ 16 - 16
Userland/DevTools/HackStudio/Git/GitRepo.cpp

@@ -24,7 +24,7 @@ GitRepo::CreateResult GitRepo::try_to_create(DeprecatedString const& repository_
 RefPtr<GitRepo> GitRepo::initialize_repository(DeprecatedString const& repository_root)
 {
     auto res = command_wrapper({ "init" }, repository_root);
-    if (res.is_null())
+    if (!res.has_value())
         return {};
 
     VERIFY(git_repo_exists(repository_root));
@@ -42,25 +42,25 @@ Vector<DeprecatedString> GitRepo::unstaged_files() const
 Vector<DeprecatedString> GitRepo::staged_files() const
 {
     auto raw_result = command({ "diff", "--cached", "--name-only" });
-    if (raw_result.is_null())
+    if (!raw_result.has_value())
         return {};
-    return parse_files_list(raw_result);
+    return parse_files_list(*raw_result);
 }
 
 Vector<DeprecatedString> GitRepo::modified_files() const
 {
     auto raw_result = command({ "ls-files", "--modified", "--exclude-standard" });
-    if (raw_result.is_null())
+    if (!raw_result.has_value())
         return {};
-    return parse_files_list(raw_result);
+    return parse_files_list(*raw_result);
 }
 
 Vector<DeprecatedString> GitRepo::untracked_files() const
 {
     auto raw_result = command({ "ls-files", "--others", "--exclude-standard" });
-    if (raw_result.is_null())
+    if (!raw_result.has_value())
         return {};
-    return parse_files_list(raw_result);
+    return parse_files_list(*raw_result);
 }
 
 Vector<DeprecatedString> GitRepo::parse_files_list(DeprecatedString const& raw_result)
@@ -73,12 +73,12 @@ Vector<DeprecatedString> GitRepo::parse_files_list(DeprecatedString const& raw_r
     return files;
 }
 
-DeprecatedString GitRepo::command(Vector<DeprecatedString> const& command_parts) const
+Optional<DeprecatedString> GitRepo::command(Vector<DeprecatedString> const& command_parts) const
 {
     return command_wrapper(command_parts, m_repository_root);
 }
 
-DeprecatedString GitRepo::command_wrapper(Vector<DeprecatedString> const& command_parts, DeprecatedString const& chdir)
+Optional<DeprecatedString> GitRepo::command_wrapper(Vector<DeprecatedString> const& command_parts, DeprecatedString const& chdir)
 {
     auto const result = Core::command("git", command_parts, LexicalPath(chdir));
     if (result.is_error() || result.value().exit_code != 0)
@@ -88,27 +88,27 @@ DeprecatedString GitRepo::command_wrapper(Vector<DeprecatedString> const& comman
 
 bool GitRepo::git_is_installed()
 {
-    return !command_wrapper({ "--help" }, "/").is_null();
+    return command_wrapper({ "--help" }, "/").has_value();
 }
 
 bool GitRepo::git_repo_exists(DeprecatedString const& repo_root)
 {
-    return !command_wrapper({ "status" }, repo_root).is_null();
+    return command_wrapper({ "status" }, repo_root).has_value();
 }
 
 bool GitRepo::stage(DeprecatedString const& file)
 {
-    return !command({ "add", file }).is_null();
+    return command({ "add", file }).has_value();
 }
 
 bool GitRepo::unstage(DeprecatedString const& file)
 {
-    return !command({ "reset", "HEAD", "--", file }).is_null();
+    return command({ "reset", "HEAD", "--", file }).has_value();
 }
 
 bool GitRepo::commit(DeprecatedString const& message)
 {
-    return !command({ "commit", "-m", message }).is_null();
+    return command({ "commit", "-m", message }).has_value();
 }
 
 Optional<DeprecatedString> GitRepo::original_file_content(DeprecatedString const& file) const
@@ -124,10 +124,10 @@ Optional<DeprecatedString> GitRepo::unstaged_diff(DeprecatedString const& file)
 bool GitRepo::is_tracked(DeprecatedString const& file) const
 {
     auto res = command({ "ls-files", file });
-    if (res.is_null())
+    if (!res.has_value())
         return false;
 
-    return !res.is_empty();
+    return !res->is_empty();
 }
 
 }

+ 2 - 2
Userland/DevTools/HackStudio/Git/GitRepo.h

@@ -45,7 +45,7 @@ private:
     static bool git_is_installed();
     static bool git_repo_exists(DeprecatedString const& repo_root);
 
-    static DeprecatedString command_wrapper(Vector<DeprecatedString> const& command_parts, DeprecatedString const& chdir);
+    static Optional<DeprecatedString> command_wrapper(Vector<DeprecatedString> const& command_parts, DeprecatedString const& chdir);
     static Vector<DeprecatedString> parse_files_list(DeprecatedString const&);
 
     explicit GitRepo(DeprecatedString const& repository_root)
@@ -56,7 +56,7 @@ private:
     Vector<DeprecatedString> modified_files() const;
     Vector<DeprecatedString> untracked_files() const;
 
-    DeprecatedString command(Vector<DeprecatedString> const& command_parts) const;
+    Optional<DeprecatedString> command(Vector<DeprecatedString> const& command_parts) const;
 
     DeprecatedString m_repository_root;
 };

+ 4 - 4
Userland/DevTools/HackStudio/HackStudioWidget.cpp

@@ -909,15 +909,15 @@ NonnullRefPtr<GUI::Action> HackStudioWidget::create_save_as_action()
 
         auto suggested_path = FileSystem::absolute_path(old_path.string()).release_value_but_fixme_should_propagate_errors();
         Optional<DeprecatedString> save_path = GUI::FilePicker::get_save_filepath(window(),
-            old_filename.is_null() ? "Untitled"sv : old_path.title(),
-            old_filename.is_null() ? "txt"sv : old_path.extension(),
+            old_filename.is_empty() ? "Untitled"sv : old_path.title(),
+            old_filename.is_empty() ? "txt"sv : old_path.extension(),
             suggested_path);
         if (!save_path.has_value()) {
             return;
         }
 
         DeprecatedString const relative_file_path = LexicalPath::relative_path(save_path.value(), m_project->root_path());
-        if (current_editor_wrapper().filename().is_null()) {
+        if (current_editor_wrapper().filename().is_empty()) {
             current_editor_wrapper().set_filename(relative_file_path);
         } else {
             for (auto& editor_wrapper : m_all_editor_wrappers) {
@@ -1729,7 +1729,7 @@ void HackStudioWidget::update_current_editor_title()
 void HackStudioWidget::on_cursor_change()
 {
     update_statusbar();
-    if (current_editor_wrapper().filename().is_null())
+    if (current_editor_wrapper().filename().is_empty())
         return;
 
     auto current_location = current_project_location();

+ 2 - 2
Userland/DevTools/HackStudio/LanguageServers/FileDB.cpp

@@ -68,9 +68,9 @@ DeprecatedString FileDB::to_absolute_path(DeprecatedString const& filename) cons
     if (LexicalPath { filename }.is_absolute()) {
         return filename;
     }
-    if (m_project_root.is_null())
+    if (!m_project_root.has_value())
         return filename;
-    return LexicalPath { DeprecatedString::formatted("{}/{}", m_project_root, filename) }.string();
+    return LexicalPath { DeprecatedString::formatted("{}/{}", *m_project_root, filename) }.string();
 }
 
 ErrorOr<NonnullRefPtr<GUI::TextDocument>> FileDB::create_from_filesystem(DeprecatedString const& filename) const

+ 1 - 1
Userland/DevTools/HackStudio/LanguageServers/FileDB.h

@@ -38,7 +38,7 @@ private:
 
 private:
     HashMap<DeprecatedString, NonnullRefPtr<GUI::TextDocument>> m_open_files;
-    DeprecatedString m_project_root;
+    Optional<DeprecatedString> m_project_root;
 };
 
 }

+ 1 - 1
Userland/DevTools/HackStudio/Locator.cpp

@@ -60,7 +60,7 @@ public:
         }
         if (suggestion.is_symbol_declaration()) {
             if (index.column() == Column::Name) {
-                if (suggestion.as_symbol_declaration.value().scope.is_null())
+                if (!suggestion.as_symbol_declaration.value().scope.is_empty())
                     return suggestion.as_symbol_declaration.value().name;
                 return DeprecatedString::formatted("{}::{}", suggestion.as_symbol_declaration.value().scope, suggestion.as_symbol_declaration.value().name);
             }

+ 3 - 3
Userland/Libraries/LibC/unistd.cpp

@@ -881,17 +881,17 @@ void sync()
     syscall(SC_sync);
 }
 
-static DeprecatedString getlogin_buffer;
+static Optional<DeprecatedString> getlogin_buffer {};
 
 char* getlogin()
 {
-    if (getlogin_buffer.is_null()) {
+    if (!getlogin_buffer.has_value()) {
         if (auto* passwd = getpwuid(getuid())) {
             getlogin_buffer = DeprecatedString(passwd->pw_name);
         }
         endpwent();
     }
-    return const_cast<char*>(getlogin_buffer.characters());
+    return const_cast<char*>(getlogin_buffer->characters());
 }
 
 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html

+ 3 - 3
Userland/Libraries/LibCodeComprehension/Cpp/CppComprehensionEngine.cpp

@@ -210,7 +210,7 @@ Vector<CodeComprehension::AutocompleteResultEntry> CppComprehensionEngine::autoc
 {
     VERIFY(parent.object());
     auto type = type_of(document, *parent.object());
-    if (type.is_null()) {
+    if (type.is_empty()) {
         dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "Could not infer type of object");
         return {};
     }
@@ -385,7 +385,7 @@ DeprecatedString CppComprehensionEngine::document_path_from_include_path(StringV
     };
 
     auto result = document_path_for_library_include(include_path);
-    if (result.is_null())
+    if (result.is_empty())
         result = document_path_for_user_defined_include(include_path);
 
     return result;
@@ -703,7 +703,7 @@ Optional<Vector<CodeComprehension::AutocompleteResultEntry>> CppComprehensionEng
             partial_include = partial_include.substring_view(0, partial_include.length() - 1).trim_whitespace();
         }
     } else if (partial_include.starts_with('"')) {
-        include_root = filedb().project_root();
+        include_root = filedb().project_root().value_or("");
         if (partial_include.length() > 1 && partial_include.ends_with('\"')) {
             already_has_suffix = true;
             partial_include = partial_include.substring_view(0, partial_include.length() - 1).trim_whitespace();

+ 2 - 2
Userland/Libraries/LibCodeComprehension/Cpp/Tests.cpp

@@ -52,8 +52,8 @@ public:
     virtual Optional<DeprecatedString> get_or_read_from_filesystem(StringView filename) const override
     {
         DeprecatedString target_filename = filename;
-        if (!project_root().is_null() && filename.starts_with(project_root())) {
-            target_filename = LexicalPath::relative_path(filename, project_root());
+        if (project_root().has_value() && filename.starts_with(*project_root())) {
+            target_filename = LexicalPath::relative_path(filename, *project_root());
         }
         return m_map.get(target_filename);
     }

+ 2 - 2
Userland/Libraries/LibCodeComprehension/FileDB.cpp

@@ -14,9 +14,9 @@ DeprecatedString FileDB::to_absolute_path(StringView filename) const
     if (LexicalPath { filename }.is_absolute()) {
         return filename;
     }
-    if (m_project_root.is_null())
+    if (!m_project_root.has_value())
         return filename;
-    return LexicalPath { DeprecatedString::formatted("{}/{}", m_project_root, filename) }.string();
+    return LexicalPath { DeprecatedString::formatted("{}/{}", *m_project_root, filename) }.string();
 }
 
 }

+ 9 - 3
Userland/Libraries/LibCodeComprehension/FileDB.h

@@ -19,15 +19,21 @@ public:
     virtual ~FileDB() = default;
 
     virtual Optional<DeprecatedString> get_or_read_from_filesystem(StringView filename) const = 0;
-    void set_project_root(StringView project_root) { m_project_root = project_root; }
-    DeprecatedString const& project_root() const { return m_project_root; }
+    void set_project_root(StringView project_root)
+    {
+        if (project_root.is_null())
+            m_project_root.clear();
+        else
+            m_project_root = project_root;
+    }
+    Optional<DeprecatedString> const& project_root() const { return m_project_root; }
     DeprecatedString to_absolute_path(StringView filename) const;
 
 protected:
     FileDB() = default;
 
 private:
-    DeprecatedString m_project_root;
+    Optional<DeprecatedString> m_project_root;
 };
 
 }

+ 13 - 11
Userland/Libraries/LibCore/Account.cpp

@@ -162,16 +162,17 @@ ErrorOr<Vector<Account>> Account::all([[maybe_unused]] Read options)
 bool Account::authenticate(SecretString const& password) const
 {
     // If there was no shadow entry for this account, authentication always fails.
-    if (m_password_hash.is_null())
+    if (!m_password_hash.has_value())
         return false;
 
     // An empty passwd field indicates that no password is required to log in.
-    if (m_password_hash.is_empty())
+    if (m_password_hash->is_empty())
         return true;
 
     // FIXME: Use crypt_r if it can be built in lagom.
-    char* hash = crypt(password.characters(), m_password_hash.characters());
-    return hash != nullptr && AK::timing_safe_compare(hash, m_password_hash.characters(), m_password_hash.length());
+    auto const bytes = m_password_hash->characters();
+    char* hash = crypt(password.characters(), bytes);
+    return hash != nullptr && AK::timing_safe_compare(hash, bytes, m_password_hash->length());
 }
 
 ErrorOr<void> Account::login() const
@@ -190,24 +191,25 @@ void Account::set_password(SecretString const& password)
 
 void Account::set_password_enabled(bool enabled)
 {
-    if (enabled && m_password_hash != "" && m_password_hash[0] == '!') {
-        m_password_hash = m_password_hash.substring(1, m_password_hash.length() - 1);
-    } else if (!enabled && (m_password_hash == "" || m_password_hash[0] != '!')) {
+    auto flattened_password_hash = m_password_hash.value_or(DeprecatedString::empty());
+    if (enabled && !flattened_password_hash.is_empty() && flattened_password_hash[0] == '!') {
+        m_password_hash = flattened_password_hash.substring(1, flattened_password_hash.length() - 1);
+    } else if (!enabled && (flattened_password_hash.is_empty() || flattened_password_hash[0] != '!')) {
         StringBuilder builder;
         builder.append('!');
-        builder.append(m_password_hash);
+        builder.append(flattened_password_hash);
         m_password_hash = builder.to_deprecated_string();
     }
 }
 
 void Account::delete_password()
 {
-    m_password_hash = "";
+    m_password_hash = DeprecatedString::empty();
 }
 
 Account::Account(passwd const& pwd, spwd const& spwd, Vector<gid_t> extra_gids)
     : m_username(pwd.pw_name)
-    , m_password_hash(spwd.sp_pwdp)
+    , m_password_hash(spwd.sp_pwdp ? Optional<DeprecatedString>(spwd.sp_pwdp) : OptionalNone {})
     , m_uid(pwd.pw_uid)
     , m_gid(pwd.pw_gid)
     , m_gecos(pwd.pw_gecos)
@@ -300,7 +302,7 @@ ErrorOr<DeprecatedString> Account::generate_shadow_file() const
         if (p->sp_namp == m_username) {
             if (m_deleted)
                 continue;
-            builder.appendff("{}:{}", m_username, m_password_hash);
+            builder.appendff("{}:{}", m_username, m_password_hash.value_or(DeprecatedString::empty()));
         } else
             builder.appendff("{}:{}", p->sp_namp, p->sp_pwdp);
 

+ 4 - 4
Userland/Libraries/LibCore/Account.h

@@ -41,7 +41,7 @@ public:
     ErrorOr<void> login() const;
 
     DeprecatedString username() const { return m_username; }
-    DeprecatedString password_hash() const { return m_password_hash; }
+    DeprecatedString password_hash() const { return m_password_hash.value_or(DeprecatedString::empty()); }
 
     // Setters only affect in-memory copy of password.
     // You must call sync to apply changes.
@@ -56,9 +56,9 @@ public:
     void set_extra_gids(Vector<gid_t> extra_gids) { m_extra_gids = move(extra_gids); }
     void delete_password();
 
-    // A null password means that this account was missing from /etc/shadow.
+    // A nonexistent password means that this account was missing from /etc/shadow.
     // It's considered to have a password in that case, and authentication will always fail.
-    bool has_password() const { return !m_password_hash.is_empty() || m_password_hash.is_null(); }
+    bool has_password() const { return !m_password_hash.has_value() || !m_password_hash->is_empty(); }
 
     uid_t uid() const { return m_uid; }
     gid_t gid() const { return m_gid; }
@@ -82,7 +82,7 @@ private:
 
     DeprecatedString m_username;
 
-    DeprecatedString m_password_hash;
+    Optional<DeprecatedString> m_password_hash;
     uid_t m_uid { 0 };
     gid_t m_gid { 0 };
     DeprecatedString m_gecos;

+ 3 - 4
Userland/Libraries/LibCore/ConfigFile.cpp

@@ -140,11 +140,10 @@ ErrorOr<void> ConfigFile::reparse()
     return {};
 }
 
-DeprecatedString ConfigFile::read_entry(DeprecatedString const& group, DeprecatedString const& key, DeprecatedString const& default_value) const
+Optional<DeprecatedString> ConfigFile::read_entry_optional(const AK::DeprecatedString& group, const AK::DeprecatedString& key) const
 {
-    if (!has_key(group, key)) {
-        return default_value;
-    }
+    if (!has_key(group, key))
+        return {};
     auto it = m_groups.find(group);
     auto jt = it->value.find(key);
     return jt->value;

+ 7 - 3
Userland/Libraries/LibCore/ConfigFile.h

@@ -42,7 +42,11 @@ public:
 
     size_t num_groups() const { return m_groups.size(); }
 
-    DeprecatedString read_entry(DeprecatedString const& group, DeprecatedString const& key, DeprecatedString const& default_value = DeprecatedString()) const;
+    DeprecatedString read_entry(DeprecatedString const& group, DeprecatedString const& key, DeprecatedString const& default_value = {}) const
+    {
+        return read_entry_optional(group, key).value_or(default_value);
+    }
+    Optional<DeprecatedString> read_entry_optional(DeprecatedString const& group, DeprecatedString const& key) const;
     bool read_bool_entry(DeprecatedString const& group, DeprecatedString const& key, bool default_value = false) const;
 
     template<Integral T = int>
@@ -52,9 +56,9 @@ public:
             return default_value;
 
         if constexpr (IsSigned<T>)
-            return read_entry(group, key).to_int<T>().value_or(default_value);
+            return read_entry(group, key, "").to_int<T>().value_or(default_value);
         else
-            return read_entry(group, key).to_uint<T>().value_or(default_value);
+            return read_entry(group, key, "").to_uint<T>().value_or(default_value);
     }
 
     void write_entry(DeprecatedString const& group, DeprecatedString const& key, DeprecatedString const& value);

+ 18 - 7
Userland/Libraries/LibCore/System.cpp

@@ -189,29 +189,40 @@ static ErrorOr<void> unveil_dynamic_loader()
 
 ErrorOr<void> unveil(StringView path, StringView permissions)
 {
-    auto const parsed_path = TRY(Core::SessionManagement::parse_path_with_sid(path));
-
     if (permissions.contains('x'))
         TRY(unveil_dynamic_loader());
 
     Syscall::SC_unveil_params params {
         static_cast<int>(UnveilFlags::CurrentProgram),
-        { parsed_path.characters(), parsed_path.length() },
-        { permissions.characters_without_null_termination(), permissions.length() },
+        { nullptr, 0 },
+        { nullptr, 0 },
     };
+
+    DeprecatedString parsed_path;
+    if (!path.is_null()) {
+        parsed_path = TRY(Core::SessionManagement::parse_path_with_sid(path));
+        params.path = { parsed_path.characters(), parsed_path.length() };
+        params.permissions = { permissions.characters_without_null_termination(), permissions.length() };
+    }
+
     int rc = syscall(SC_unveil, &params);
     HANDLE_SYSCALL_RETURN_VALUE("unveil", rc, {});
 }
 
 ErrorOr<void> unveil_after_exec(StringView path, StringView permissions)
 {
-    auto const parsed_path = TRY(Core::SessionManagement::parse_path_with_sid(path));
-
+    DeprecatedString parsed_path;
     Syscall::SC_unveil_params params {
         static_cast<int>(UnveilFlags::AfterExec),
-        { parsed_path.characters(), parsed_path.length() },
+        { nullptr, 0 },
         { permissions.characters_without_null_termination(), permissions.length() },
     };
+
+    if (!path.is_null()) {
+        parsed_path = TRY(Core::SessionManagement::parse_path_with_sid(path));
+        params.path = { parsed_path.characters(), parsed_path.length() };
+    }
+
     int rc = syscall(SC_unveil, &params);
     HANDLE_SYSCALL_RETURN_VALUE("unveil", rc, {});
 }

+ 1 - 1
Userland/Libraries/LibCore/SystemServerTakeover.cpp

@@ -41,7 +41,7 @@ ErrorOr<NonnullOwnPtr<Core::LocalSocket>> take_over_socket_from_system_server(De
         parse_sockets_from_system_server();
 
     int fd;
-    if (socket_path.is_null()) {
+    if (socket_path.is_empty()) {
         // We want the first (and only) socket.
         VERIFY(s_overtaken_sockets.size() == 1);
         fd = s_overtaken_sockets.begin()->value;

+ 2 - 2
Userland/Libraries/LibCpp/Preprocessor.cpp

@@ -102,7 +102,7 @@ void Preprocessor::handle_preprocessor_statement(StringView line)
     consume_whitespace(lexer);
     auto keyword = lexer.consume_until(' ');
     lexer.ignore();
-    if (keyword.is_empty() || keyword.is_null() || keyword.is_whitespace())
+    if (keyword.is_empty() || keyword.is_whitespace())
         return;
 
     handle_preprocessor_keyword(keyword, lexer);
@@ -243,7 +243,7 @@ void Preprocessor::handle_preprocessor_keyword(StringView keyword, GenericLexer&
 
 size_t Preprocessor::do_substitution(Vector<Token> const& tokens, size_t token_index, Definition const& defined_value)
 {
-    if (defined_value.value.is_null())
+    if (defined_value.value.is_empty())
         return token_index;
 
     Substitution sub;

+ 1 - 1
Userland/Libraries/LibDNS/Packet.cpp

@@ -161,7 +161,7 @@ Optional<Packet> Packet::from_raw_packet(u8 const* raw_data, size_t raw_size)
         case RecordType::AAAA:
             // Fall through
         case RecordType::SRV:
-            data = { record.data(), record.data_length() };
+            data = ReadonlyBytes { record.data(), record.data_length() };
             break;
         default:
             // FIXME: Parse some other record types perhaps?

+ 1 - 1
Userland/Libraries/LibDebug/DebugInfo.cpp

@@ -95,7 +95,7 @@ ErrorOr<void> DebugInfo::prepare_lines()
     auto compute_full_path = [&](DeprecatedFlyString const& file_path) -> Optional<DeprecatedString> {
         if (file_path.view().contains("Toolchain/"sv) || file_path.view().contains("libgcc"sv))
             return {};
-        if (file_path.view().starts_with("./"sv) && !m_source_root.is_null())
+        if (file_path.view().starts_with("./"sv) && !m_source_root.is_empty())
             return LexicalPath::join(m_source_root, file_path).string();
         if (auto index_of_serenity_slash = file_path.view().find("serenity/"sv); index_of_serenity_slash.has_value()) {
             auto start_index = index_of_serenity_slash.value() + "serenity/"sv.length();

+ 1 - 1
Userland/Libraries/LibELF/Image.cpp

@@ -455,7 +455,7 @@ DeprecatedString Image::symbolicate(FlatPtr address, u32* out_offset) const
     }
 
     auto& demangled_name = symbol->demangled_name;
-    if (demangled_name.is_null())
+    if (demangled_name.is_empty())
         demangled_name = demangle(symbol->name);
 
     if (out_offset) {

+ 1 - 1
Userland/Libraries/LibFileSystemAccessClient/Client.cpp

@@ -98,7 +98,7 @@ Result Client::save_file(GUI::Window* parent_window, DeprecatedString const& nam
         GUI::ConnectionToWindowServer::the().remove_window_stealing_for_client(child_window_server_client_id, parent_window_id);
     });
 
-    async_prompt_save_file(id, parent_window_server_client_id, parent_window_id, name.is_null() ? "Untitled" : name, ext.is_null() ? "txt" : ext, Core::StandardPaths::home_directory(), requested_access);
+    async_prompt_save_file(id, parent_window_server_client_id, parent_window_id, name.is_empty() ? "Untitled" : name, ext.is_empty() ? "txt" : ext, Core::StandardPaths::home_directory(), requested_access);
 
     return handle_promise(id);
 }

+ 13 - 10
Userland/Libraries/LibGUI/AbstractView.cpp

@@ -89,9 +89,11 @@ void AbstractView::model_did_update(unsigned int flags)
             m_drop_candidate_index = {};
         selection().remove_all_matching([this](auto& index) { return !model()->is_within_range(index); });
 
-        auto index = find_next_search_match(m_highlighted_search.view());
-        if (index.is_valid())
-            highlight_search(index);
+        if (m_highlighted_search.has_value()) {
+            auto index = find_next_search_match(m_highlighted_search->view());
+            if (index.is_valid())
+                highlight_search(index);
+        }
     }
     m_selection_start_index = {};
 }
@@ -592,11 +594,11 @@ void AbstractView::keydown_event(KeyEvent& event)
 
     if (is_searchable()) {
         if (event.key() == KeyCode::Key_Backspace) {
-            if (!m_highlighted_search.is_null()) {
+            if (m_highlighted_search.has_value()) {
                 // if (event.modifiers() == Mod_Ctrl) {
                 //  TODO: delete last word
                 // }
-                Utf8View view(m_highlighted_search);
+                Utf8View view(*m_highlighted_search);
                 size_t n_code_points = view.length();
                 if (n_code_points > 1) {
                     n_code_points--;
@@ -621,7 +623,7 @@ void AbstractView::keydown_event(KeyEvent& event)
                 return;
             }
         } else if (event.key() == KeyCode::Key_Escape) {
-            if (!m_highlighted_search.is_null()) {
+            if (m_highlighted_search.has_value()) {
                 stop_highlighted_search_timer();
 
                 event.accept();
@@ -629,7 +631,8 @@ void AbstractView::keydown_event(KeyEvent& event)
             }
         } else if (event.key() != KeyCode::Key_Tab && !event.ctrl() && !event.alt() && event.code_point() != 0) {
             StringBuilder sb;
-            sb.append(m_highlighted_search);
+            if (m_highlighted_search.has_value())
+                sb.append(*m_highlighted_search);
             sb.append_code_point(event.code_point());
 
             auto index = find_next_search_match(sb.string_view());
@@ -650,7 +653,7 @@ void AbstractView::keydown_event(KeyEvent& event)
 
 void AbstractView::stop_highlighted_search_timer()
 {
-    m_highlighted_search = nullptr;
+    m_highlighted_search.clear();
     if (m_highlighted_search_timer)
         m_highlighted_search_timer->stop();
     if (m_highlighted_search_index.is_valid()) {
@@ -723,8 +726,8 @@ void AbstractView::draw_item_text(Gfx::Painter& painter, ModelIndex const& index
         text_color = index.data(ModelRole::ForegroundColor).to_color(palette().color(foreground_role()));
 
     if (index == m_highlighted_search_index) {
-        auto const byte_offset = search_highlighting_offset < m_highlighted_search.length() ? 0 : item_text.length();
-        auto const byte_length = min(item_text.length() - byte_offset, m_highlighted_search.length() - search_highlighting_offset);
+        auto const byte_offset = search_highlighting_offset < m_highlighted_search.value_or("").length() ? 0 : item_text.length();
+        auto const byte_length = min(item_text.length() - byte_offset, m_highlighted_search.value_or("").length() - search_highlighting_offset);
         Utf8View const searching_text(item_text.substring_view(byte_offset, byte_length));
 
         // Highlight the text background first

+ 1 - 1
Userland/Libraries/LibGUI/AbstractView.h

@@ -199,7 +199,7 @@ private:
 
     RefPtr<Model> m_model;
     ModelSelection m_selection;
-    DeprecatedString m_highlighted_search;
+    Optional<DeprecatedString> m_highlighted_search;
     RefPtr<Core::Timer> m_highlighted_search_timer;
     SelectionBehavior m_selection_behavior { SelectionBehavior::SelectItems };
     SelectionMode m_selection_mode { SelectionMode::SingleSelection };

+ 8 - 18
Userland/Libraries/LibGUI/FilePicker.cpp

@@ -48,9 +48,10 @@ ErrorOr<Optional<String>> FilePicker::get_filepath(Badge<FileSystemAccessServer:
     ConnectionToWindowServer::the().set_window_parent_from_client(window_server_client_id, parent_window_id, picker->window_id());
 
     if (picker->exec() == ExecResult::OK) {
-        auto file_path = TRY(String::from_deprecated_string(picker->selected_file()));
-        if (file_path.is_empty())
+        auto file_path = TRY(picker->selected_file().map([](auto& v) { return String::from_deprecated_string(v); }));
+        if (file_path.has_value() && file_path->is_empty())
             return Optional<String> {};
+
         return file_path;
     }
     return Optional<String> {};
@@ -60,17 +61,12 @@ Optional<DeprecatedString> FilePicker::get_open_filepath(Window* parent_window,
 {
     auto picker = FilePicker::construct(parent_window, folder ? Mode::OpenFolder : Mode::Open, ""sv, path, screen_position, move(allowed_file_types));
 
-    if (!window_title.is_null())
+    if (!window_title.is_empty())
         picker->set_title(window_title);
 
-    if (picker->exec() == ExecResult::OK) {
-        DeprecatedString file_path = picker->selected_file();
-
-        if (file_path.is_null())
-            return {};
+    if (picker->exec() == ExecResult::OK)
+        return picker->selected_file();
 
-        return file_path;
-    }
     return {};
 }
 
@@ -78,14 +74,8 @@ Optional<DeprecatedString> FilePicker::get_save_filepath(Window* parent_window,
 {
     auto picker = FilePicker::construct(parent_window, Mode::Save, DeprecatedString::formatted("{}.{}", title, extension), path, screen_position);
 
-    if (picker->exec() == ExecResult::OK) {
-        DeprecatedString file_path = picker->selected_file();
-
-        if (file_path.is_null())
-            return {};
-
-        return file_path;
-    }
+    if (picker->exec() == ExecResult::OK)
+        return picker->selected_file();
     return {};
 }
 

+ 2 - 2
Userland/Libraries/LibGUI/FilePicker.h

@@ -44,7 +44,7 @@ public:
 
     virtual ~FilePicker() override;
 
-    DeprecatedString const& selected_file() const { return m_selected_file; }
+    Optional<DeprecatedString> const& selected_file() const { return m_selected_file; }
 
 private:
     void on_file_return();
@@ -77,7 +77,7 @@ private:
 
     RefPtr<MultiView> m_view;
     NonnullRefPtr<FileSystemModel> m_model;
-    DeprecatedString m_selected_file;
+    Optional<DeprecatedString> m_selected_file;
 
     Vector<DeprecatedString> m_allowed_file_types_names;
     Optional<Vector<FileTypeFilter>> m_allowed_file_types;

+ 3 - 3
Userland/Libraries/LibGUI/FileSystemModel.cpp

@@ -68,7 +68,7 @@ bool FileSystemModel::Node::fetch_data(DeprecatedString const& full_path, bool i
             perror("readlink");
         else {
             symlink_target = sym_link_target_or_error.release_value().to_deprecated_string();
-            if (symlink_target.is_null())
+            if (symlink_target.is_empty())
                 perror("readlink");
         }
     }
@@ -364,7 +364,7 @@ void FileSystemModel::update_node_on_selection(ModelIndex const& index, bool con
 
 void FileSystemModel::set_root_path(DeprecatedString root_path)
 {
-    if (root_path.is_null())
+    if (root_path.is_empty())
         m_root_path = {};
     else
         m_root_path = LexicalPath::canonicalized_path(move(root_path));
@@ -382,7 +382,7 @@ void FileSystemModel::invalidate()
 {
     m_root = adopt_own(*new Node(*this));
 
-    if (m_root_path.is_null())
+    if (m_root_path.is_empty())
         m_root->m_parent_of_root = true;
 
     m_root->reify_if_needed();

+ 4 - 1
Userland/Libraries/LibGUI/ModelEditingDelegate.h

@@ -96,7 +96,10 @@ public:
     virtual void set_value(Variant const& value, SelectionBehavior selection_behavior) override
     {
         auto& textbox = static_cast<TextBox&>(*widget());
-        textbox.set_text(value.to_deprecated_string());
+        if (value.is_valid())
+            textbox.set_text(value.to_deprecated_string());
+        else
+            textbox.clear();
         if (selection_behavior == SelectionBehavior::SelectAll)
             textbox.select_all();
     }

+ 2 - 2
Userland/Libraries/LibGUI/TableView.cpp

@@ -202,10 +202,10 @@ void TableView::keydown_event(KeyEvent& event)
                 if (selection().size() > 1) {
                     selection().for_each_index([&](GUI::ModelIndex& index) {
                         begin_editing(index);
-                        m_editing_delegate->set_value(DeprecatedString {});
+                        m_editing_delegate->set_value(GUI::Variant {});
                     });
                 } else {
-                    m_editing_delegate->set_value(DeprecatedString {});
+                    m_editing_delegate->set_value(GUI::Variant {});
                 }
             } else if (is_backspace) {
                 m_editing_delegate->set_value(DeprecatedString::empty());

+ 0 - 1
Userland/Libraries/LibGUI/Variant.h

@@ -98,7 +98,6 @@ public:
         return visit(
             [](Empty) { return false; },
             [](Detail::Boolean v) { return v.value; },
-            [](DeprecatedString const& v) { return !v.is_null(); },
             [](Integral auto v) { return v != 0; },
             [](Gfx::IntPoint const& v) { return !v.is_zero(); },
             [](OneOf<Gfx::IntRect, Gfx::IntSize> auto const& v) { return !v.is_empty(); },

+ 1 - 1
Userland/Libraries/LibGemini/Line.cpp

@@ -69,7 +69,7 @@ Link::Link(DeprecatedString text, Document const& document)
         m_name = url_string.substring_view(offset, url_string.length() - offset);
     }
     m_url = document.url().complete_url(url);
-    if (m_name.is_null())
+    if (m_name.is_empty())
         m_name = m_url.to_deprecated_string();
 }
 

+ 0 - 14
Userland/Libraries/LibHTTP/Job.cpp

@@ -249,10 +249,6 @@ void Job::on_socket_connected()
             auto line = maybe_line.release_value();
 
             dbgln_if(JOB_DEBUG, "Job {} read line of length {}", m_request.url(), line.length());
-            if (line.is_null()) {
-                dbgln("Job: Expected HTTP status");
-                return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::TransmissionFailed); });
-            }
             auto parts = line.split_view(' ');
             if (parts.size() < 2) {
                 dbgln("Job: Expected 2-part or 3-part HTTP status line, got '{}'", line);
@@ -302,16 +298,6 @@ void Job::on_socket_connected()
             }
             auto line = maybe_line.release_value();
 
-            if (line.is_null()) {
-                if (m_state == State::Trailers) {
-                    // Some servers like to send two ending chunks
-                    // use this fact as an excuse to ignore anything after the last chunk
-                    // that is not a valid trailing header.
-                    return finish_up();
-                }
-                dbgln("Job: Expected HTTP header");
-                return did_fail(Core::NetworkJob::Error::ProtocolFailed);
-            }
             if (line.is_empty()) {
                 if (m_state == State::Trailers) {
                     return finish_up();

+ 14 - 14
Userland/Libraries/LibJS/Runtime/JSONObject.cpp

@@ -45,7 +45,7 @@ void JSONObject::initialize(Realm& realm)
 }
 
 // 25.5.2 JSON.stringify ( value [ , replacer [ , space ] ] ), https://tc39.es/ecma262/#sec-json.stringify
-ThrowCompletionOr<DeprecatedString> JSONObject::stringify_impl(VM& vm, Value value, Value replacer, Value space)
+ThrowCompletionOr<Optional<DeprecatedString>> JSONObject::stringify_impl(VM& vm, Value value, Value replacer, Value space)
 {
     auto& realm = *vm.current_realm();
 
@@ -62,7 +62,7 @@ ThrowCompletionOr<DeprecatedString> JSONObject::stringify_impl(VM& vm, Value val
                 Vector<DeprecatedString> list;
                 for (size_t i = 0; i < replacer_length; ++i) {
                     auto replacer_value = TRY(replacer_object.get(i));
-                    DeprecatedString item;
+                    Optional<DeprecatedString> item;
                     if (replacer_value.is_string()) {
                         item = replacer_value.as_string().deprecated_string();
                     } else if (replacer_value.is_number()) {
@@ -72,8 +72,8 @@ ThrowCompletionOr<DeprecatedString> JSONObject::stringify_impl(VM& vm, Value val
                         if (is<StringObject>(value_object) || is<NumberObject>(value_object))
                             item = TRY(replacer_value.to_deprecated_string(vm));
                     }
-                    if (!item.is_null() && !list.contains_slow(item)) {
-                        list.append(item);
+                    if (item.has_value() && !list.contains_slow(*item)) {
+                        list.append(*item);
                     }
                 }
                 state.property_list = list;
@@ -118,15 +118,15 @@ JS_DEFINE_NATIVE_FUNCTION(JSONObject::stringify)
     auto replacer = vm.argument(1);
     auto space = vm.argument(2);
 
-    auto string = TRY(stringify_impl(vm, value, replacer, space));
-    if (string.is_null())
+    auto maybe_string = TRY(stringify_impl(vm, value, replacer, space));
+    if (!maybe_string.has_value())
         return js_undefined();
 
-    return PrimitiveString::create(vm, string);
+    return PrimitiveString::create(vm, maybe_string.release_value());
 }
 
 // 25.5.2.1 SerializeJSONProperty ( state, key, holder ), https://tc39.es/ecma262/#sec-serializejsonproperty
-ThrowCompletionOr<DeprecatedString> JSONObject::serialize_json_property(VM& vm, StringifyState& state, PropertyKey const& key, Object* holder)
+ThrowCompletionOr<Optional<DeprecatedString>> JSONObject::serialize_json_property(VM& vm, StringifyState& state, PropertyKey const& key, Object* holder)
 {
     // 1. Let value be ? Get(holder, key).
     auto value = TRY(holder->get(key));
@@ -209,14 +209,14 @@ ThrowCompletionOr<DeprecatedString> JSONObject::serialize_json_property(VM& vm,
 
         // b. If isArray is true, return ? SerializeJSONArray(state, value).
         if (is_array)
-            return serialize_json_array(vm, state, value.as_object());
+            return TRY(serialize_json_array(vm, state, value.as_object()));
 
         // c. Return ? SerializeJSONObject(state, value).
-        return serialize_json_object(vm, state, value.as_object());
+        return TRY(serialize_json_object(vm, state, value.as_object()));
     }
 
     // 12. Return undefined.
-    return DeprecatedString {};
+    return Optional<DeprecatedString> {};
 }
 
 // 25.5.2.4 SerializeJSONObject ( state, value ), https://tc39.es/ecma262/#sec-serializejsonobject
@@ -234,7 +234,7 @@ ThrowCompletionOr<DeprecatedString> JSONObject::serialize_json_object(VM& vm, St
         if (key.is_symbol())
             return {};
         auto serialized_property_string = TRY(serialize_json_property(vm, state, key, &object));
-        if (!serialized_property_string.is_null()) {
+        if (serialized_property_string.has_value()) {
             property_strings.append(DeprecatedString::formatted(
                 "{}:{}{}",
                 quote_json_string(key.to_string()),
@@ -305,10 +305,10 @@ ThrowCompletionOr<DeprecatedString> JSONObject::serialize_json_array(VM& vm, Str
 
     for (size_t i = 0; i < length; ++i) {
         auto serialized_property_string = TRY(serialize_json_property(vm, state, i, &object));
-        if (serialized_property_string.is_null()) {
+        if (!serialized_property_string.has_value()) {
             property_strings.append("null"sv);
         } else {
-            property_strings.append(serialized_property_string);
+            property_strings.append(serialized_property_string.release_value());
         }
     }
 

+ 2 - 2
Userland/Libraries/LibJS/Runtime/JSONObject.h

@@ -19,7 +19,7 @@ public:
 
     // The base implementation of stringify is exposed because it is used by
     // test-js to communicate between the JS tests and the C++ test runner.
-    static ThrowCompletionOr<DeprecatedString> stringify_impl(VM&, Value value, Value replacer, Value space);
+    static ThrowCompletionOr<Optional<DeprecatedString>> stringify_impl(VM&, Value value, Value replacer, Value space);
 
     static Value parse_json_value(VM&, JsonValue const&);
 
@@ -35,7 +35,7 @@ private:
     };
 
     // Stringify helpers
-    static ThrowCompletionOr<DeprecatedString> serialize_json_property(VM&, StringifyState&, PropertyKey const& key, Object* holder);
+    static ThrowCompletionOr<Optional<DeprecatedString>> serialize_json_property(VM&, StringifyState&, PropertyKey const& key, Object* holder);
     static ThrowCompletionOr<DeprecatedString> serialize_json_object(VM&, StringifyState&, Object&);
     static ThrowCompletionOr<DeprecatedString> serialize_json_array(VM&, StringifyState&, Object&);
     static DeprecatedString quote_json_string(DeprecatedString);

+ 1 - 1
Userland/Libraries/LibJS/Runtime/PrimitiveString.cpp

@@ -221,7 +221,7 @@ NonnullGCPtr<PrimitiveString> PrimitiveString::create(VM& vm, DeprecatedString s
 
 NonnullGCPtr<PrimitiveString> PrimitiveString::create(VM& vm, DeprecatedFlyString const& string)
 {
-    return create(vm, string.impl());
+    return create(vm, *string.impl());
 }
 
 NonnullGCPtr<PrimitiveString> PrimitiveString::create(VM& vm, PrimitiveString& lhs, PrimitiveString& rhs)

+ 1 - 1
Userland/Libraries/LibJS/Runtime/VM.cpp

@@ -910,7 +910,7 @@ ThrowCompletionOr<NonnullGCPtr<Module>> VM::resolve_imported_module(ScriptOrModu
     VERIFY(module_request.assertions.is_empty() || (module_request.assertions.size() == 1 && module_request.assertions.first().key == "type"));
     auto module_type = module_request.assertions.is_empty() ? DeprecatedString {} : module_request.assertions.first().value;
 
-    dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] module at {} has type {} [is_null={}]", module_request.module_specifier, module_type, module_type.is_null());
+    dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] module at {} has type {}", module_request.module_specifier, module_type);
 
     StringView base_filename = referencing_script_or_module.visit(
         [&](Empty) {

+ 3 - 3
Userland/Libraries/LibJS/Token.cpp

@@ -174,7 +174,7 @@ DeprecatedString Token::string_value(StringValueStatus& status) const
 
         // In non-strict mode LegacyOctalEscapeSequence is allowed in strings:
         // https://tc39.es/ecma262/#sec-additional-syntax-string-literals
-        DeprecatedString octal_str;
+        Optional<DeprecatedString> octal_str;
 
         auto is_octal_digit = [](char ch) { return ch >= '0' && ch <= '7'; };
         auto is_zero_to_three = [](char ch) { return ch >= '0' && ch <= '3'; };
@@ -193,9 +193,9 @@ DeprecatedString Token::string_value(StringValueStatus& status) const
         else if (is_zero_to_three(lexer.peek()) && is_octal_digit(lexer.peek(1)) && is_octal_digit(lexer.peek(2)))
             octal_str = lexer.consume(3);
 
-        if (!octal_str.is_null()) {
+        if (octal_str.has_value()) {
             status = StringValueStatus::LegacyOctalEscapeSequence;
-            auto code_point = strtoul(octal_str.characters(), nullptr, 8);
+            auto code_point = strtoul(octal_str->characters(), nullptr, 8);
             VERIFY(code_point <= 255);
             builder.append_code_point(code_point);
             continue;

+ 0 - 2
Userland/Libraries/LibPDF/Parser.cpp

@@ -256,8 +256,6 @@ NonnullRefPtr<StringObject> Parser::parse_string()
         is_binary_string = true;
     }
 
-    VERIFY(!string.is_null());
-
     auto string_object = make_object<StringObject>(string, is_binary_string);
 
     if (m_document->security_handler() && m_enable_encryption)

+ 3 - 3
Userland/Libraries/LibSQL/AST/AST.h

@@ -186,8 +186,8 @@ public:
 
     ResultType type() const { return m_type; }
 
-    bool select_from_table() const { return !m_table_name.is_null(); }
-    DeprecatedString const& table_name() const { return m_table_name; }
+    bool select_from_table() const { return m_table_name.has_value(); }
+    Optional<DeprecatedString> const& table_name() const { return m_table_name; }
 
     bool select_from_expression() const { return !m_expression.is_null(); }
     RefPtr<Expression> const& expression() const { return m_expression; }
@@ -196,7 +196,7 @@ public:
 private:
     ResultType m_type { ResultType::All };
 
-    DeprecatedString m_table_name {};
+    Optional<DeprecatedString> m_table_name {};
 
     RefPtr<Expression> m_expression {};
     DeprecatedString m_column_alias {};

+ 7 - 7
Userland/Libraries/LibSQL/AST/Parser.cpp

@@ -566,16 +566,16 @@ RefPtr<Expression> Parser::parse_bind_parameter_expression()
     return {};
 }
 
-RefPtr<Expression> Parser::parse_column_name_expression(DeprecatedString with_parsed_identifier, bool with_parsed_period)
+RefPtr<Expression> Parser::parse_column_name_expression(Optional<DeprecatedString> with_parsed_identifier, bool with_parsed_period)
 {
-    if (with_parsed_identifier.is_null() && !match(TokenType::Identifier))
+    if (!with_parsed_identifier.has_value() && !match(TokenType::Identifier))
         return {};
 
     DeprecatedString first_identifier;
-    if (with_parsed_identifier.is_null())
+    if (!with_parsed_identifier.has_value())
         first_identifier = consume(TokenType::Identifier).value();
     else
-        first_identifier = move(with_parsed_identifier);
+        first_identifier = with_parsed_identifier.release_value();
 
     DeprecatedString schema_name;
     DeprecatedString table_name;
@@ -1010,17 +1010,17 @@ NonnullRefPtr<ResultColumn> Parser::parse_result_column()
     // If we match an identifier now, we don't know whether it is a table-name of the form "table-name.*", or if it is the start of a
     // column-name-expression, until we try to parse the asterisk. So if we consume an identifier and a period, but don't find an
     // asterisk, hold onto that information to form a column-name-expression later.
-    DeprecatedString table_name;
+    Optional<DeprecatedString> table_name;
     bool parsed_period = false;
 
     if (match(TokenType::Identifier)) {
         table_name = consume().value();
         parsed_period = consume_if(TokenType::Period);
         if (parsed_period && consume_if(TokenType::Asterisk))
-            return create_ast_node<ResultColumn>(move(table_name));
+            return create_ast_node<ResultColumn>(table_name.release_value());
     }
 
-    auto expression = table_name.is_null()
+    auto expression = !table_name.has_value()
         ? parse_expression()
         : static_cast<NonnullRefPtr<Expression>>(*parse_column_name_expression(move(table_name), parsed_period));
 

+ 1 - 1
Userland/Libraries/LibSQL/AST/Parser.h

@@ -74,7 +74,7 @@ private:
     bool match_secondary_expression() const;
     RefPtr<Expression> parse_literal_value_expression();
     RefPtr<Expression> parse_bind_parameter_expression();
-    RefPtr<Expression> parse_column_name_expression(DeprecatedString with_parsed_identifier = {}, bool with_parsed_period = false);
+    RefPtr<Expression> parse_column_name_expression(Optional<DeprecatedString> with_parsed_identifier = {}, bool with_parsed_period = false);
     RefPtr<Expression> parse_unary_operator_expression();
     RefPtr<Expression> parse_binary_operator_expression(NonnullRefPtr<Expression> lhs);
     RefPtr<Expression> parse_chained_expression(bool surrounded_by_parentheses = true);

+ 2 - 2
Userland/Libraries/LibTLS/Handshake.cpp

@@ -44,7 +44,7 @@ ByteBuffer TLSv12::build_hello()
     size_t alpn_negotiated_length = 0;
 
     // ALPN
-    if (!m_context.negotiated_alpn.is_null()) {
+    if (!m_context.negotiated_alpn.is_empty()) {
         alpn_negotiated_length = m_context.negotiated_alpn.length();
         alpn_length = alpn_negotiated_length + 1;
         extension_length += alpn_length + 6;
@@ -69,7 +69,7 @@ ByteBuffer TLSv12::build_hello()
 
     // set SNI if we have one, and the user hasn't explicitly asked us to omit it.
     auto sni_length = 0;
-    if (!m_context.extensions.SNI.is_null() && m_context.options.use_sni)
+    if (!m_context.extensions.SNI.is_empty() && m_context.options.use_sni)
         sni_length = m_context.extensions.SNI.length();
 
     auto elliptic_curves_length = 2 * m_context.options.elliptic_curves.size();

+ 4 - 3
Userland/Libraries/LibTest/JavaScriptTestRunner.h

@@ -247,9 +247,10 @@ inline AK::Result<JS::NonnullGCPtr<JS::SourceTextModule>, ParserError> parse_mod
 inline ErrorOr<JsonValue> get_test_results(JS::Realm& realm)
 {
     auto results = MUST(realm.global_object().get("__TestResults__"));
-    auto json_string = MUST(JS::JSONObject::stringify_impl(*g_vm, results, JS::js_undefined(), JS::js_undefined()));
-
-    return JsonValue::from_string(json_string);
+    auto maybe_json_string = MUST(JS::JSONObject::stringify_impl(*g_vm, results, JS::js_undefined(), JS::js_undefined()));
+    if (maybe_json_string.has_value())
+        return JsonValue::from_string(*maybe_json_string);
+    return JsonValue();
 }
 
 inline void TestRunner::do_run_single_test(DeprecatedString const& test_path, size_t, size_t)

+ 1 - 1
Userland/Libraries/LibVT/Attribute.h

@@ -38,7 +38,7 @@ struct Attribute {
 
 #ifndef KERNEL
     DeprecatedString href;
-    DeprecatedString href_id;
+    Optional<DeprecatedString> href_id;
 #endif
 
     enum class Flags : u8 {

+ 7 - 7
Userland/Libraries/LibVT/TerminalWidget.cpp

@@ -292,7 +292,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event)
 
     // Pass: Compute the rect(s) of the currently hovered link, if any.
     Vector<Gfx::IntRect> hovered_href_rects;
-    if (!m_hovered_href_id.is_null()) {
+    if (m_hovered_href_id.has_value()) {
         for (u16 visual_row = 0; visual_row < m_terminal.rows(); ++visual_row) {
             auto& line = m_terminal.line(first_row_from_history + visual_row);
             for (size_t column = 0; column < line.length(); ++column) {
@@ -415,7 +415,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event)
 
             auto character_rect = glyph_rect(visual_row, column);
 
-            if (!m_hovered_href_id.is_null() && attribute.href_id == m_hovered_href_id) {
+            if (m_hovered_href_id.has_value() && attribute.href_id == m_hovered_href_id) {
                 text_color = palette().base_text();
             }
 
@@ -754,7 +754,7 @@ void TerminalWidget::doubleclick_event(GUI::MouseEvent& event)
 {
     if (event.button() == GUI::MouseButton::Primary) {
         auto attribute = m_terminal.attribute_at(buffer_position_at(event.position()));
-        if (!attribute.href_id.is_null()) {
+        if (attribute.href_id.has_value()) {
             dbgln("Open hyperlinked URL: '{}'", attribute.href);
             Desktop::Launcher::open(attribute.href);
             return;
@@ -806,7 +806,7 @@ void TerminalWidget::copy()
 void TerminalWidget::mouseup_event(GUI::MouseEvent& event)
 {
     if (event.button() == GUI::MouseButton::Primary) {
-        if (!m_active_href_id.is_null()) {
+        if (m_active_href_id.has_value()) {
             m_active_href = {};
             m_active_href_id = {};
             update();
@@ -862,7 +862,7 @@ void TerminalWidget::mousemove_event(GUI::MouseEvent& event)
     auto attribute = m_terminal.attribute_at(position);
 
     if (attribute.href_id != m_hovered_href_id) {
-        if (!attribute.href_id.is_null()) {
+        if (attribute.href_id.has_value()) {
             m_hovered_href_id = attribute.href_id;
             m_hovered_href = attribute.href;
 
@@ -902,7 +902,7 @@ void TerminalWidget::mousemove_event(GUI::MouseEvent& event)
     if (!(event.buttons() & GUI::MouseButton::Primary))
         return;
 
-    if (!m_active_href_id.is_null()) {
+    if (m_active_href_id.has_value()) {
         auto diff = event.position() - m_left_mousedown_position;
         auto distance_travelled_squared = diff.x() * diff.x() + diff.y() * diff.y();
         constexpr int drag_distance_threshold = 5;
@@ -1111,7 +1111,7 @@ void TerminalWidget::set_cursor_shape(CursorShape shape)
 
 void TerminalWidget::context_menu_event(GUI::ContextMenuEvent& event)
 {
-    if (m_hovered_href_id.is_null()) {
+    if (!m_hovered_href_id.has_value()) {
         m_context_menu->popup(event.screen_position());
     } else {
         m_context_menu_href = m_hovered_href;

+ 2 - 2
Userland/Libraries/LibVT/TerminalWidget.h

@@ -168,10 +168,10 @@ private:
     VT::Range m_selection;
 
     DeprecatedString m_hovered_href;
-    DeprecatedString m_hovered_href_id;
+    Optional<DeprecatedString> m_hovered_href_id;
 
     DeprecatedString m_active_href;
-    DeprecatedString m_active_href_id;
+    Optional<DeprecatedString> m_active_href_id;
 
     // Snapshot of m_hovered_href when opening a context menu for a hyperlink.
     DeprecatedString m_context_menu_href;

+ 1 - 1
Userland/Libraries/LibWeb/CSS/CSSNamespaceRule.cpp

@@ -40,7 +40,7 @@ DeprecatedString CSSNamespaceRule::serialized() const
     builder.append("@namespace "sv);
 
     // followed by the serialization as an identifier of the prefix attribute (if any),
-    if (!m_prefix.is_empty() && !m_prefix.is_null()) {
+    if (!m_prefix.is_empty()) {
         serialize_an_identifier(builder, m_prefix);
         // followed by a single SPACE (U+0020) if there is a prefix,
         builder.append(" "sv);

+ 5 - 5
Userland/Libraries/LibWeb/CSS/CSSStyleRule.cpp

@@ -53,23 +53,23 @@ DeprecatedString CSSStyleRule::serialized() const
     builder.append(" {"sv);
 
     // 2. Let decls be the result of performing serialize a CSS declaration block on the rule’s associated declarations, or null if there are no such declarations.
-    auto decls = declaration().serialized();
+    auto decls = declaration().length() > 0 ? declaration().serialized() : Optional<DeprecatedString>();
 
     // FIXME: 3. Let rules be the result of performing serialize a CSS rule on each rule in the rule’s cssRules list, or null if there are no such rules.
-    DeprecatedString rules;
+    Optional<DeprecatedString> rules;
 
     // 4. If decls and rules are both null, append " }" to s (i.e. a single SPACE (U+0020) followed by RIGHT CURLY BRACKET (U+007D)) and return s.
-    if (decls.is_null() && rules.is_null()) {
+    if (!decls.has_value() && !rules.has_value()) {
         builder.append(" }"sv);
         return builder.to_deprecated_string();
     }
 
     // 5. If rules is null:
-    if (rules.is_null()) {
+    if (!rules.has_value()) {
         //    1. Append a single SPACE (U+0020) to s
         builder.append(' ');
         //    2. Append decls to s
-        builder.append(decls);
+        builder.append(*decls);
         //    3. Append " }" to s (i.e. a single SPACE (U+0020) followed by RIGHT CURLY BRACKET (U+007D)).
         builder.append(" }"sv);
         //    4. Return s.

+ 3 - 3
Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp

@@ -36,9 +36,9 @@ static inline bool matches_lang_pseudo_class(DOM::Element const& element, Vector
 {
     FlyString element_language;
     for (auto const* e = &element; e; e = e->parent_element()) {
-        auto lang = e->deprecated_attribute(HTML::AttributeNames::lang);
-        if (!lang.is_null()) {
-            element_language = FlyString::from_deprecated_fly_string(lang).release_value_but_fixme_should_propagate_errors();
+        auto lang = e->attribute(HTML::AttributeNames::lang);
+        if (lang.has_value()) {
+            element_language = lang.release_value();
             break;
         }
     }

+ 3 - 3
Userland/Libraries/LibWeb/DOM/Attr.cpp

@@ -92,7 +92,7 @@ void Attr::change_attribute(String value)
 }
 
 // https://dom.spec.whatwg.org/#handle-attribute-changes
-void Attr::handle_attribute_changes(Element& element, DeprecatedString const& old_value, DeprecatedString const& new_value)
+void Attr::handle_attribute_changes(Element& element, Optional<DeprecatedString> old_value, Optional<DeprecatedString> new_value)
 {
     DeprecatedString deprecated_namespace_uri;
     if (namespace_uri().has_value())
@@ -107,8 +107,8 @@ void Attr::handle_attribute_changes(Element& element, DeprecatedString const& ol
 
         JS::MarkedVector<JS::Value> arguments { vm.heap() };
         arguments.append(JS::PrimitiveString::create(vm, local_name()));
-        arguments.append(old_value.is_null() ? JS::js_null() : JS::PrimitiveString::create(vm, old_value));
-        arguments.append(new_value.is_null() ? JS::js_null() : JS::PrimitiveString::create(vm, new_value));
+        arguments.append(!old_value.has_value() ? JS::js_null() : JS::PrimitiveString::create(vm, old_value.release_value()));
+        arguments.append(!new_value.has_value() ? JS::js_null() : JS::PrimitiveString::create(vm, new_value.release_value()));
         arguments.append(!namespace_uri().has_value() ? JS::js_null() : JS::PrimitiveString::create(vm, namespace_uri().value()));
 
         element.enqueue_a_custom_element_callback_reaction(HTML::CustomElementReactionNames::attributeChangedCallback, move(arguments));

+ 1 - 1
Userland/Libraries/LibWeb/DOM/Attr.h

@@ -41,7 +41,7 @@ public:
     // Always returns true: https://dom.spec.whatwg.org/#dom-attr-specified
     constexpr bool specified() const { return true; }
 
-    void handle_attribute_changes(Element&, DeprecatedString const& old_value, DeprecatedString const& new_value);
+    void handle_attribute_changes(Element&, Optional<DeprecatedString> old_value, Optional<DeprecatedString> new_value);
 
 private:
     Attr(Document&, QualifiedName, String value, Element*);

+ 15 - 13
Userland/Libraries/LibWeb/DOM/Element.cpp

@@ -82,19 +82,19 @@ Element::Element(Document& document, DOM::QualifiedName qualified_name)
                 return;
 
             // 2. If value is null and oldValue is the empty string, then return.
-            if (value.is_null() && old_value == DeprecatedString::empty())
+            if (!value.has_value() && old_value == DeprecatedString::empty())
                 return;
 
             // 3. If value is the empty string and oldValue is null, then return.
-            if (value == DeprecatedString::empty() && old_value.is_null())
+            if (value == DeprecatedString::empty() && !old_value.has_value())
                 return;
 
             // 4. If value is null or the empty string, then set element’s name to the empty string.
-            if (value.is_empty())
+            if (!value.has_value() || value->is_empty())
                 set_slottable_name({});
             // 5. Otherwise, set element’s name to value.
             else
-                set_slottable_name(MUST(String::from_deprecated_string(value)));
+                set_slottable_name(MUST(String::from_deprecated_string(*value)));
 
             // 6. If element is assigned, then run assign slottables for element’s assigned slot.
             if (auto assigned_slot = assigned_slot_internal())
@@ -468,7 +468,7 @@ void Element::add_attribute_change_steps(AttributeChangeSteps steps)
     m_attribute_change_steps.append(move(steps));
 }
 
-void Element::run_attribute_change_steps(FlyString const& local_name, DeprecatedString const& old_value, DeprecatedString const& value, DeprecatedFlyString const& namespace_)
+void Element::run_attribute_change_steps(FlyString const& local_name, Optional<DeprecatedString> const& old_value, Optional<DeprecatedString> const& value, DeprecatedFlyString const& namespace_)
 {
     for (auto const& attribute_change_steps : m_attribute_change_steps)
         attribute_change_steps(local_name, old_value, value, namespace_);
@@ -478,19 +478,21 @@ void Element::run_attribute_change_steps(FlyString const& local_name, Deprecated
     invalidate_style_after_attribute_change(local_name);
 }
 
-void Element::attribute_changed(FlyString const& name, DeprecatedString const& value)
+void Element::attribute_changed(FlyString const& name, Optional<DeprecatedString> const& value)
 {
+    auto value_or_empty = value.value_or("");
+
     if (name == HTML::AttributeNames::class_) {
-        auto new_classes = value.split_view(Infra::is_ascii_whitespace);
+        auto new_classes = value_or_empty.split_view(Infra::is_ascii_whitespace);
         m_classes.clear();
         m_classes.ensure_capacity(new_classes.size());
         for (auto& new_class : new_classes) {
             m_classes.unchecked_append(FlyString::from_utf8(new_class).release_value_but_fixme_should_propagate_errors());
         }
         if (m_class_list)
-            m_class_list->associated_attribute_changed(value);
+            m_class_list->associated_attribute_changed(value_or_empty);
     } else if (name == HTML::AttributeNames::style) {
-        if (value.is_null()) {
+        if (!value.has_value()) {
             if (!m_inline_style) {
                 m_inline_style = nullptr;
                 set_needs_style_update(true);
@@ -499,16 +501,16 @@ void Element::attribute_changed(FlyString const& name, DeprecatedString const& v
             // https://drafts.csswg.org/cssom/#ref-for-cssstyledeclaration-updating-flag
             if (m_inline_style && m_inline_style->is_updating())
                 return;
-            m_inline_style = parse_css_style_attribute(CSS::Parser::ParsingContext(document()), value, *this);
+            m_inline_style = parse_css_style_attribute(CSS::Parser::ParsingContext(document()), *value, *this);
             set_needs_style_update(true);
         }
     } else if (name == HTML::AttributeNames::dir) {
         // https://html.spec.whatwg.org/multipage/dom.html#attr-dir
-        if (value.equals_ignoring_ascii_case("ltr"sv))
+        if (value_or_empty.equals_ignoring_ascii_case("ltr"sv))
             m_dir = Dir::Ltr;
-        else if (value.equals_ignoring_ascii_case("rtl"sv))
+        else if (value_or_empty.equals_ignoring_ascii_case("rtl"sv))
             m_dir = Dir::Rtl;
-        else if (value.equals_ignoring_ascii_case("auto"sv))
+        else if (value_or_empty.equals_ignoring_ascii_case("auto"sv))
             m_dir = Dir::Auto;
         else
             m_dir = {};

+ 3 - 3
Userland/Libraries/LibWeb/DOM/Element.h

@@ -153,11 +153,11 @@ public:
     virtual void apply_presentational_hints(CSS::StyleProperties&) const { }
 
     // https://dom.spec.whatwg.org/#concept-element-attributes-change-ext
-    using AttributeChangeSteps = Function<void(FlyString const& /*local_name*/, DeprecatedString const& /*old_value*/, DeprecatedString const& /*value*/, DeprecatedFlyString const& /*namespace_*/)>;
+    using AttributeChangeSteps = Function<void(FlyString const& /*local_name*/, Optional<DeprecatedString> const& /*old_value*/, Optional<DeprecatedString> const& /*value*/, DeprecatedFlyString const& /*namespace_*/)>;
 
     void add_attribute_change_steps(AttributeChangeSteps steps);
-    void run_attribute_change_steps(FlyString const& local_name, DeprecatedString const& old_value, DeprecatedString const& value, DeprecatedFlyString const& namespace_);
-    virtual void attribute_changed(FlyString const& name, DeprecatedString const& value);
+    void run_attribute_change_steps(FlyString const& local_name, Optional<DeprecatedString> const& old_value, Optional<DeprecatedString> const& value, DeprecatedFlyString const& namespace_);
+    virtual void attribute_changed(FlyString const& name, Optional<DeprecatedString> const& value);
 
     struct [[nodiscard]] RequiredInvalidationAfterStyleChange {
         bool repaint { false };

+ 8 - 16
Userland/Libraries/LibWeb/DOM/Node.cpp

@@ -1533,7 +1533,7 @@ Painting::PaintableBox* Node::paintable_box()
 }
 
 // https://dom.spec.whatwg.org/#queue-a-mutation-record
-void Node::queue_mutation_record(FlyString const& type, DeprecatedString attribute_name, DeprecatedString attribute_namespace, DeprecatedString old_value, Vector<JS::Handle<Node>> added_nodes, Vector<JS::Handle<Node>> removed_nodes, Node* previous_sibling, Node* next_sibling) const
+void Node::queue_mutation_record(FlyString const& type, Optional<DeprecatedString> attribute_name, Optional<DeprecatedString> attribute_namespace, Optional<DeprecatedString> old_value, Vector<JS::Handle<Node>> added_nodes, Vector<JS::Handle<Node>> removed_nodes, Node* previous_sibling, Node* next_sibling) const
 {
     // NOTE: We defer garbage collection until the end of the scope, since we can't safely use MutationObserver* as a hashmap key otherwise.
     // FIXME: This is a total hack.
@@ -1541,7 +1541,7 @@ void Node::queue_mutation_record(FlyString const& type, DeprecatedString attribu
 
     // 1. Let interestedObservers be an empty map.
     // mutationObserver -> mappedOldValue
-    OrderedHashMap<MutationObserver*, DeprecatedString> interested_observers;
+    OrderedHashMap<MutationObserver*, Optional<DeprecatedString>> interested_observers;
 
     // 2. Let nodes be the inclusive ancestors of target.
     Vector<JS::Handle<Node const>> nodes;
@@ -1565,7 +1565,7 @@ void Node::queue_mutation_record(FlyString const& type, DeprecatedString attribu
             //    then:
             if (!(node.ptr() != this && !options.subtree)
                 && !(type == MutationType::attributes && (!options.attributes.has_value() || !options.attributes.value()))
-                && !(type == MutationType::attributes && options.attribute_filter.has_value() && (!attribute_namespace.is_null() || !options.attribute_filter->contains_slow(attribute_name.view())))
+                && !(type == MutationType::attributes && options.attribute_filter.has_value() && (attribute_namespace.has_value() || !options.attribute_filter->contains_slow(attribute_name.value_or("").view())))
                 && !(type == MutationType::characterData && (!options.character_data.has_value() || !options.character_data.value()))
                 && !(type == MutationType::childList && !options.child_list)) {
                 // 1. Let mo be registered’s observer.
@@ -1593,17 +1593,9 @@ void Node::queue_mutation_record(FlyString const& type, DeprecatedString attribu
     for (auto& interested_observer : interested_observers) {
         // 1. Let record be a new MutationRecord object with its type set to type, target set to target, attributeName set to name, attributeNamespace set to namespace, oldValue set to mappedOldValue,
         //    addedNodes set to addedNodes, removedNodes set to removedNodes, previousSibling set to previousSibling, and nextSibling set to nextSibling.
-        Optional<String> maybe_attribute_name;
-        if (!attribute_name.is_null())
-            maybe_attribute_name = MUST(String::from_deprecated_string(attribute_name));
-
-        Optional<String> maybe_attribute_namespace;
-        if (!attribute_namespace.is_null())
-            maybe_attribute_namespace = MUST(String::from_deprecated_string(attribute_namespace));
-
-        Optional<String> maybe_interested_observer;
-        if (!interested_observer.value.is_null())
-            maybe_interested_observer = MUST(String::from_deprecated_string(interested_observer.value));
+        auto maybe_attribute_name = attribute_name.map([](auto& name) { return MUST(String::from_deprecated_string(name)); });
+        auto maybe_attribute_namespace = attribute_namespace.map([](auto& ns) { return MUST(String::from_deprecated_string(ns)); });
+        auto maybe_interested_observer = interested_observer.value.map([](auto& value) { return MUST(String::from_deprecated_string(value)); });
 
         auto record = MutationRecord::create(realm(), type, *this, added_nodes_list, removed_nodes_list, previous_sibling, next_sibling, maybe_attribute_name, maybe_attribute_namespace, /* mappedOldValue */ maybe_interested_observer);
 
@@ -1888,8 +1880,8 @@ ErrorOr<String> Node::name_or_description(NameOrDescription target, Document con
     if (is<HTML::HTMLElement>(this)) {
         auto const* element = static_cast<HTML::HTMLElement const*>(this);
         auto tooltip = element->title();
-        if (!tooltip.is_empty() && !tooltip.is_null())
-            return String::from_deprecated_string(tooltip);
+        if (!tooltip.has_value() && !tooltip->is_empty())
+            return tooltip.release_value();
     }
     // Append the result of each step above, with a space, to the total accumulated text.
     //

+ 1 - 1
Userland/Libraries/LibWeb/DOM/Node.h

@@ -259,7 +259,7 @@ public:
 
     void add_registered_observer(RegisteredObserver& registered_observer) { m_registered_observer_list.append(registered_observer); }
 
-    void queue_mutation_record(FlyString const& type, DeprecatedString attribute_name, DeprecatedString attribute_namespace, DeprecatedString old_value, Vector<JS::Handle<Node>> added_nodes, Vector<JS::Handle<Node>> removed_nodes, Node* previous_sibling, Node* next_sibling) const;
+    void queue_mutation_record(FlyString const& type, Optional<DeprecatedString> attribute_name, Optional<DeprecatedString> attribute_namespace, Optional<DeprecatedString> old_value, Vector<JS::Handle<Node>> added_nodes, Vector<JS::Handle<Node>> removed_nodes, Node* previous_sibling, Node* next_sibling) const;
 
     // https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-descendant
     template<typename Callback>

+ 6 - 9
Userland/Libraries/LibWeb/DOM/StyleElementUtils.cpp

@@ -43,8 +43,8 @@ void StyleElementUtils::update_a_style_block(DOM::Element& style_element)
         return;
 
     // 4. If element's type attribute is present and its value is neither the empty string nor an ASCII case-insensitive match for "text/css", then return.
-    auto type_attribute = style_element.deprecated_attribute(HTML::AttributeNames::type);
-    if (!type_attribute.is_null() && !type_attribute.is_empty() && !Infra::is_ascii_case_insensitive_match(type_attribute, "text/css"sv))
+    auto type_attribute = style_element.attribute(HTML::AttributeNames::type);
+    if (type_attribute.has_value() && !type_attribute->is_empty() && !Infra::is_ascii_case_insensitive_match(type_attribute->bytes_as_string_view(), "text/css"sv))
         return;
 
     // FIXME: 5. If the Should element's inline behavior be blocked by Content Security Policy? algorithm returns "Blocked" when executed upon the style element, "style", and the style element's child text content, then return. [CSP]
@@ -86,7 +86,7 @@ void StyleElementUtils::remove_a_css_style_sheet(DOM::Document& document, CSS::C
 }
 
 // https://www.w3.org/TR/cssom/#create-a-css-style-sheet
-void StyleElementUtils::create_a_css_style_sheet(DOM::Document& document, DeprecatedString type, DOM::Element* owner_node, DeprecatedString media, DeprecatedString title, bool alternate, bool origin_clean, DeprecatedString location, CSS::CSSStyleSheet* parent_style_sheet, CSS::CSSRule* owner_rule, CSS::CSSStyleSheet& sheet)
+void StyleElementUtils::create_a_css_style_sheet(DOM::Document& document, DeprecatedString type, DOM::Element* owner_node, DeprecatedString media, DeprecatedString title, bool alternate, bool origin_clean, Optional<DeprecatedString> location, CSS::CSSStyleSheet* parent_style_sheet, CSS::CSSRule* owner_rule, CSS::CSSStyleSheet& sheet)
 {
     // 1. Create a new CSS style sheet object and set its properties as specified.
     // FIXME: We receive `sheet` from the caller already. This is weird.
@@ -96,16 +96,13 @@ void StyleElementUtils::create_a_css_style_sheet(DOM::Document& document, Deprec
     sheet.set_owner_node(owner_node);
     sheet.set_type(MUST(String::from_deprecated_string(type)));
     sheet.set_media(move(media));
-    if (title.is_null())
-        sheet.set_title({});
-    else
-        sheet.set_title(MUST(String::from_deprecated_string(title)));
+    sheet.set_title(MUST(String::from_deprecated_string(title)));
     sheet.set_alternate(alternate);
     sheet.set_origin_clean(origin_clean);
-    if (location.is_null())
+    if (!location.has_value())
         sheet.set_location({});
     else
-        sheet.set_location(MUST(String::from_deprecated_string(location)));
+        sheet.set_location(MUST(String::from_deprecated_string(*location)));
 
     // 2. Then run the add a CSS style sheet steps for the newly created CSS style sheet.
     add_a_css_style_sheet(document, sheet);

+ 1 - 1
Userland/Libraries/LibWeb/DOM/StyleElementUtils.h

@@ -20,7 +20,7 @@ public:
 
 private:
     void remove_a_css_style_sheet(DOM::Document& document, CSS::CSSStyleSheet& sheet);
-    void create_a_css_style_sheet(DOM::Document& document, DeprecatedString type, DOM::Element* owner_node, DeprecatedString media, DeprecatedString title, bool alternate, bool origin_clean, DeprecatedString location, CSS::CSSStyleSheet* parent_style_sheet, CSS::CSSRule* owner_rule, CSS::CSSStyleSheet& sheet);
+    void create_a_css_style_sheet(DOM::Document& document, DeprecatedString type, DOM::Element* owner_node, DeprecatedString media, DeprecatedString title, bool alternate, bool origin_clean, Optional<DeprecatedString> location, CSS::CSSStyleSheet* parent_style_sheet, CSS::CSSRule* owner_rule, CSS::CSSStyleSheet& sheet);
     void add_a_css_style_sheet(DOM::Document& document, CSS::CSSStyleSheet& sheet);
 
     // https://www.w3.org/TR/cssom/#associated-css-style-sheet

+ 8 - 6
Userland/Libraries/LibWeb/DOMParsing/XMLSerializer.cpp

@@ -257,14 +257,14 @@ static Optional<DeprecatedString> record_namespace_information(DOM::Element cons
             auto const& prefix_definition = attribute->local_name().to_deprecated_fly_string();
 
             // 2. Let namespace definition be the value of attr's value.
-            auto namespace_definition = attribute->value().to_deprecated_string();
+            DeprecatedFlyString namespace_definition = attribute->value().to_deprecated_string();
 
             // 3. If namespace definition is the XML namespace, then stop running these steps, and return to Main to visit the next attribute.
             if (namespace_definition == Namespace::XML)
                 continue;
 
             // 4. If namespace definition is the empty string (the declarative form of having no namespace), then let namespace definition be null instead.
-            if (namespace_definition.is_empty())
+            if (namespace_definition == ""sv)
                 namespace_definition = {};
 
             // 5. If prefix definition is found in map given the namespace namespace definition, then stop running these steps, and return to Main to visit the next attribute.
@@ -284,17 +284,19 @@ static Optional<DeprecatedString> record_namespace_information(DOM::Element cons
 }
 
 // https://w3c.github.io/DOM-Parsing/#dfn-serializing-an-attribute-value
-static WebIDL::ExceptionOr<DeprecatedString> serialize_an_attribute_value(DeprecatedString const& attribute_value, [[maybe_unused]] RequireWellFormed require_well_formed)
+static WebIDL::ExceptionOr<DeprecatedString> serialize_an_attribute_value(OneOf<DeprecatedString, DeprecatedFlyString> auto const& attribute_value, [[maybe_unused]] RequireWellFormed require_well_formed)
 {
     // FIXME: 1. If the require well-formed flag is set (its value is true), and attribute value contains characters that are not matched by the XML Char production,
     //           then throw an exception; the serialization of this attribute value would fail to produce a well-formed element serialization.
 
     // 2. If attribute value is null, then return the empty string.
-    if (attribute_value.is_null())
-        return DeprecatedString::empty();
+    if constexpr (requires { attribute_value.is_null(); }) {
+        if (attribute_value.is_null())
+            return DeprecatedString::empty();
+    }
 
     // 3. Otherwise, attribute value is a string. Return the value of attribute value, first replacing any occurrences of the following:
-    auto final_attribute_value = attribute_value;
+    DeprecatedString final_attribute_value = attribute_value;
 
     // 1. "&" with "&amp;"
     final_attribute_value = final_attribute_value.replace("&"sv, "&amp;"sv, ReplaceMode::All);

+ 1 - 1
Userland/Libraries/LibWeb/Dump.cpp

@@ -821,7 +821,7 @@ ErrorOr<void> dump_namespace_rule(StringBuilder& builder, CSS::CSSNamespaceRule
 {
     indent(builder, indent_levels);
     TRY(builder.try_appendff("  Namespace: {}\n", namespace_.namespace_uri()));
-    if (!namespace_.prefix().is_null() && !namespace_.prefix().is_empty())
+    if (!namespace_.prefix().is_empty())
         TRY(builder.try_appendff("  Prefix: {}\n", namespace_.prefix()));
 
     return {};

+ 4 - 4
Userland/Libraries/LibWeb/HTML/HTMLAnchorElement.cpp

@@ -27,7 +27,7 @@ void HTMLAnchorElement::initialize(JS::Realm& realm)
     set_prototype(&Bindings::ensure_web_prototype<Bindings::HTMLAnchorElementPrototype>(realm, "HTMLAnchorElement"));
 }
 
-void HTMLAnchorElement::attribute_changed(FlyString const& name, DeprecatedString const& value)
+void HTMLAnchorElement::attribute_changed(FlyString const& name, Optional<DeprecatedString> const& value)
 {
     HTMLElement::attribute_changed(name, value);
     if (name == HTML::AttributeNames::href) {
@@ -35,9 +35,9 @@ void HTMLAnchorElement::attribute_changed(FlyString const& name, DeprecatedStrin
     }
 }
 
-DeprecatedString HTMLAnchorElement::hyperlink_element_utils_href() const
+Optional<String> HTMLAnchorElement::hyperlink_element_utils_href() const
 {
-    return deprecated_attribute(HTML::AttributeNames::href);
+    return attribute(HTML::AttributeNames::href);
 }
 
 WebIDL::ExceptionOr<void> HTMLAnchorElement::set_hyperlink_element_utils_href(String href)
@@ -98,7 +98,7 @@ i32 HTMLAnchorElement::default_tab_index_value() const
 Optional<ARIA::Role> HTMLAnchorElement::default_role() const
 {
     // https://www.w3.org/TR/html-aria/#el-a-no-href
-    if (!href().is_null())
+    if (!href().is_empty())
         return ARIA::Role::link;
     // https://www.w3.org/TR/html-aria/#el-a
     return ARIA::Role::generic;

+ 2 - 2
Userland/Libraries/LibWeb/HTML/HTMLAnchorElement.h

@@ -43,12 +43,12 @@ private:
     void run_activation_behavior(Web::DOM::Event const&);
 
     // ^DOM::Element
-    virtual void attribute_changed(FlyString const& name, DeprecatedString const& value) override;
+    virtual void attribute_changed(FlyString const& name, Optional<DeprecatedString> const& value) override;
     virtual i32 default_tab_index_value() const override;
 
     // ^HTML::HTMLHyperlinkElementUtils
     virtual DOM::Document& hyperlink_element_utils_document() override { return document(); }
-    virtual DeprecatedString hyperlink_element_utils_href() const override;
+    virtual Optional<String> hyperlink_element_utils_href() const override;
     virtual WebIDL::ExceptionOr<void> set_hyperlink_element_utils_href(String) override;
     virtual bool hyperlink_element_utils_is_html_anchor_element() const final { return true; }
     virtual bool hyperlink_element_utils_is_connected() const final { return is_connected(); }

+ 4 - 4
Userland/Libraries/LibWeb/HTML/HTMLAreaElement.cpp

@@ -23,7 +23,7 @@ void HTMLAreaElement::initialize(JS::Realm& realm)
     set_prototype(&Bindings::ensure_web_prototype<Bindings::HTMLAreaElementPrototype>(realm, "HTMLAreaElement"));
 }
 
-void HTMLAreaElement::attribute_changed(FlyString const& name, DeprecatedString const& value)
+void HTMLAreaElement::attribute_changed(FlyString const& name, Optional<DeprecatedString> const& value)
 {
     HTMLElement::attribute_changed(name, value);
     if (name == HTML::AttributeNames::href) {
@@ -31,9 +31,9 @@ void HTMLAreaElement::attribute_changed(FlyString const& name, DeprecatedString
     }
 }
 
-DeprecatedString HTMLAreaElement::hyperlink_element_utils_href() const
+Optional<String> HTMLAreaElement::hyperlink_element_utils_href() const
 {
-    return deprecated_attribute(HTML::AttributeNames::href);
+    return attribute(HTML::AttributeNames::href);
 }
 
 WebIDL::ExceptionOr<void> HTMLAreaElement::set_hyperlink_element_utils_href(String href)
@@ -51,7 +51,7 @@ i32 HTMLAreaElement::default_tab_index_value() const
 Optional<ARIA::Role> HTMLAreaElement::default_role() const
 {
     // https://www.w3.org/TR/html-aria/#el-area-no-href
-    if (!href().is_null())
+    if (!href().is_empty())
         return ARIA::Role::link;
     // https://www.w3.org/TR/html-aria/#el-area
     return ARIA::Role::generic;

+ 2 - 2
Userland/Libraries/LibWeb/HTML/HTMLAreaElement.h

@@ -26,12 +26,12 @@ private:
     virtual void initialize(JS::Realm&) override;
 
     // ^DOM::Element
-    virtual void attribute_changed(FlyString const& name, DeprecatedString const& value) override;
+    virtual void attribute_changed(FlyString const& name, Optional<DeprecatedString> const& value) override;
     virtual i32 default_tab_index_value() const override;
 
     // ^HTML::HTMLHyperlinkElementUtils
     virtual DOM::Document& hyperlink_element_utils_document() override { return document(); }
-    virtual DeprecatedString hyperlink_element_utils_href() const override;
+    virtual Optional<String> hyperlink_element_utils_href() const override;
     virtual WebIDL::ExceptionOr<void> set_hyperlink_element_utils_href(String) override;
     virtual bool hyperlink_element_utils_is_html_anchor_element() const override { return false; }
     virtual bool hyperlink_element_utils_is_connected() const override { return is_connected(); }

+ 1 - 1
Userland/Libraries/LibWeb/HTML/HTMLBaseElement.cpp

@@ -43,7 +43,7 @@ void HTMLBaseElement::removed_from(Node* parent)
     document().update_base_element({});
 }
 
-void HTMLBaseElement::attribute_changed(FlyString const& name, DeprecatedString const& value)
+void HTMLBaseElement::attribute_changed(FlyString const& name, Optional<DeprecatedString> const& value)
 {
     HTMLElement::attribute_changed(name, value);
 

+ 1 - 1
Userland/Libraries/LibWeb/HTML/HTMLBaseElement.h

@@ -23,7 +23,7 @@ public:
 
     virtual void inserted() override;
     virtual void removed_from(Node*) override;
-    virtual void attribute_changed(FlyString const& name, DeprecatedString const& value) override;
+    virtual void attribute_changed(FlyString const& name, Optional<DeprecatedString> const& value) override;
 
 private:
     HTMLBaseElement(DOM::Document&, DOM::QualifiedName);

+ 8 - 8
Userland/Libraries/LibWeb/HTML/HTMLBodyElement.cpp

@@ -55,26 +55,26 @@ void HTMLBodyElement::apply_presentational_hints(CSS::StyleProperties& style) co
     });
 }
 
-void HTMLBodyElement::attribute_changed(FlyString const& name, DeprecatedString const& value)
+void HTMLBodyElement::attribute_changed(FlyString const& name, Optional<DeprecatedString> const& value)
 {
     HTMLElement::attribute_changed(name, value);
     if (name.equals_ignoring_ascii_case("link"sv)) {
         // https://html.spec.whatwg.org/multipage/rendering.html#the-page:rules-for-parsing-a-legacy-colour-value-3
-        auto color = parse_legacy_color_value(value);
+        auto color = parse_legacy_color_value(value.value_or(""));
         if (color.has_value())
             document().set_link_color(color.value());
     } else if (name.equals_ignoring_ascii_case("alink"sv)) {
         // https://html.spec.whatwg.org/multipage/rendering.html#the-page:rules-for-parsing-a-legacy-colour-value-5
-        auto color = parse_legacy_color_value(value);
+        auto color = parse_legacy_color_value(value.value_or(""));
         if (color.has_value())
             document().set_active_link_color(color.value());
     } else if (name.equals_ignoring_ascii_case("vlink"sv)) {
         // https://html.spec.whatwg.org/multipage/rendering.html#the-page:rules-for-parsing-a-legacy-colour-value-4
-        auto color = parse_legacy_color_value(value);
+        auto color = parse_legacy_color_value(value.value_or(""));
         if (color.has_value())
             document().set_visited_link_color(color.value());
     } else if (name.equals_ignoring_ascii_case("background"sv)) {
-        m_background_style_value = CSS::ImageStyleValue::create(document().parse_url(value));
+        m_background_style_value = CSS::ImageStyleValue::create(document().parse_url(value.value_or("")));
         m_background_style_value->on_animate = [this] {
             if (layout_node()) {
                 layout_node()->set_needs_display();
@@ -83,9 +83,9 @@ void HTMLBodyElement::attribute_changed(FlyString const& name, DeprecatedString
     }
 
 #undef __ENUMERATE
-#define __ENUMERATE(attribute_name, event_name)                                                                     \
-    if (name == HTML::AttributeNames::attribute_name) {                                                             \
-        element_event_handler_attribute_changed(event_name, String::from_deprecated_string(value).release_value()); \
+#define __ENUMERATE(attribute_name, event_name)                                                                                          \
+    if (name == HTML::AttributeNames::attribute_name) {                                                                                  \
+        element_event_handler_attribute_changed(event_name, value.map([](auto& v) { return MUST(String::from_deprecated_string(v)); })); \
     }
     ENUMERATE_WINDOW_EVENT_HANDLERS(__ENUMERATE)
 #undef __ENUMERATE

+ 1 - 1
Userland/Libraries/LibWeb/HTML/HTMLBodyElement.h

@@ -20,7 +20,7 @@ class HTMLBodyElement final
 public:
     virtual ~HTMLBodyElement() override;
 
-    virtual void attribute_changed(FlyString const&, DeprecatedString const&) override;
+    virtual void attribute_changed(FlyString const&, Optional<DeprecatedString> const&) override;
     virtual void apply_presentational_hints(CSS::StyleProperties&) const override;
 
     // https://www.w3.org/TR/html-aria/#el-body

Неке датотеке нису приказане због велике количине промена