LCOV - code coverage report
Current view: top level - gjs - deprecation.cpp (source / functions) Coverage Total Hit
Test: gjs- Code Coverage Lines: 84.3 % 51 43
Test Date: 2024-04-16 04:37:39 Functions: 85.7 % 7 6
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 45.8 % 24 11

             Branch data     Line data    Source code
       1                 :             : /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
       2                 :             : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
       3                 :             : // SPDX-FileCopyrightText: 2018 Philip Chimento <philip.chimento@gmail.com>
       4                 :             : 
       5                 :             : #include <config.h>
       6                 :             : 
       7                 :             : #include <cstddef>        // for size_t
       8                 :             : #include <functional>     // for hash<int>
       9                 :             : #include <sstream>
      10                 :             : #include <string>         // for string
      11                 :             : #include <string_view>
      12                 :             : #include <unordered_set>  // for unordered_set
      13                 :             : #include <utility>        // for move
      14                 :             : #include <vector>
      15                 :             : 
      16                 :             : #include <glib.h>  // for g_warning
      17                 :             : 
      18                 :             : #include <js/CharacterEncoding.h>
      19                 :             : #include <js/Conversions.h>
      20                 :             : #include <js/RootingAPI.h>
      21                 :             : #include <js/Stack.h>  // for CaptureCurrentStack, MaxFrames
      22                 :             : #include <js/TypeDecls.h>
      23                 :             : #include <js/Utility.h>  // for UniqueChars
      24                 :             : #include <js/Value.h>
      25                 :             : #include <js/friend/DumpFunctions.h>
      26                 :             : 
      27                 :             : #include "gjs/deprecation.h"
      28                 :             : #include "gjs/macros.h"
      29                 :             : 
      30                 :             : const char* messages[] = {
      31                 :             :     // None:
      32                 :             :     "(invalid message)",
      33                 :             : 
      34                 :             :     // ByteArrayInstanceToString:
      35                 :             :     "Some code called array.toString() on a Uint8Array instance. Previously "
      36                 :             :     "this would have interpreted the bytes of the array as a string, but that "
      37                 :             :     "is nonstandard. In the future this will return the bytes as "
      38                 :             :     "comma-separated digits. For the time being, the old behavior has been "
      39                 :             :     "preserved, but please fix your code anyway to use TextDecoder.\n"
      40                 :             :     "(Note that array.toString() may have been called implicitly.)",
      41                 :             : 
      42                 :             :     // DeprecatedGObjectProperty:
      43                 :             :     "The GObject property {}.{} is deprecated.",
      44                 :             : 
      45                 :             :     // ModuleExportedLetOrConst:
      46                 :             :     "Some code accessed the property '{}' on the module '{}'. That property "
      47                 :             :     "was defined with 'let' or 'const' inside the module. This was previously "
      48                 :             :     "supported, but is not correct according to the ES6 standard. Any symbols "
      49                 :             :     "to be exported from a module must be defined with 'var'. The property "
      50                 :             :     "access will work as previously for the time being, but please fix your "
      51                 :             :     "code anyway.",
      52                 :             : 
      53                 :             :     // PlatformSpecificTypelib:
      54                 :             :     ("{} has been moved to a separate platform-specific library. Please update "
      55                 :             :      "your code to use {} instead."),
      56                 :             : };
      57                 :             : 
      58                 :             : static_assert(G_N_ELEMENTS(messages) == GjsDeprecationMessageId::LastValue);
      59                 :             : 
      60                 :             : struct DeprecationEntry {
      61                 :             :     GjsDeprecationMessageId id;
      62                 :             :     std::string loc;
      63                 :             : 
      64                 :           4 :     DeprecationEntry(GjsDeprecationMessageId an_id, const char* a_loc)
      65                 :           8 :         : id(an_id), loc(a_loc) {}
      66                 :             : 
      67                 :           0 :     bool operator==(const DeprecationEntry& other) const {
      68   [ #  #  #  # ]:           0 :         return id == other.id && loc == other.loc;
      69                 :             :     }
      70                 :             : };
      71                 :             : 
      72                 :             : namespace std {
      73                 :             : template <>
      74                 :             : struct hash<DeprecationEntry> {
      75                 :           6 :     size_t operator()(const DeprecationEntry& key) const {
      76                 :           6 :         return hash<int>()(key.id) ^ hash<std::string>()(key.loc);
      77                 :             :     }
      78                 :             : };
      79                 :             : };  // namespace std
      80                 :             : 
      81                 :             : static std::unordered_set<DeprecationEntry> logged_messages;
      82                 :             : 
      83                 :             : GJS_JSAPI_RETURN_CONVENTION
      84                 :           4 : static JS::UniqueChars get_callsite(JSContext* cx) {
      85                 :           4 :     JS::RootedObject stack_frame(cx);
      86                 :           4 :     if (!JS::CaptureCurrentStack(cx, &stack_frame,
      87   [ +  -  +  -  :          12 :                                  JS::StackCapture(JS::MaxFrames(1))) ||
                   -  + ]
      88         [ -  + ]:           4 :         !stack_frame)
      89                 :           0 :         return nullptr;
      90                 :             : 
      91                 :           4 :     JS::RootedValue v_frame(cx, JS::ObjectValue(*stack_frame));
      92                 :           4 :     JS::RootedString frame_string(cx, JS::ToString(cx, v_frame));
      93         [ -  + ]:           4 :     if (!frame_string)
      94                 :           0 :         return nullptr;
      95                 :             : 
      96                 :           4 :     return JS_EncodeStringToUTF8(cx, frame_string);
      97                 :           4 : }
      98                 :             : 
      99                 :           4 : static void warn_deprecated_unsafe_internal(JSContext* cx,
     100                 :             :                                             const GjsDeprecationMessageId id,
     101                 :             :                                             const char* msg) {
     102                 :           4 :     JS::UniqueChars callsite(get_callsite(cx));
     103                 :           4 :     DeprecationEntry entry(id, callsite.get());
     104         [ +  - ]:           4 :     if (!logged_messages.count(entry)) {
     105                 :             :         JS::UniqueChars stack_dump =
     106                 :           4 :             JS::FormatStackDump(cx, false, false, false);
     107                 :           4 :         g_warning("%s\n%s", msg, stack_dump.get());
     108                 :           4 :         logged_messages.insert(std::move(entry));
     109                 :           4 :     }
     110                 :           4 : }
     111                 :             : 
     112                 :             : /* Note, this can only be called from the JS thread because it uses the full
     113                 :             :  * stack dump API and not the "safe" gjs_dumpstack() which can only print to
     114                 :             :  * stdout or stderr. Do not use this function during GC, for example. */
     115                 :           2 : void _gjs_warn_deprecated_once_per_callsite(JSContext* cx,
     116                 :             :                                             const GjsDeprecationMessageId id) {
     117                 :           2 :     warn_deprecated_unsafe_internal(cx, id, messages[id]);
     118                 :           2 : }
     119                 :             : 
     120                 :           2 : void _gjs_warn_deprecated_once_per_callsite(
     121                 :             :     JSContext* cx, GjsDeprecationMessageId id,
     122                 :             :     const std::vector<const char*>& args) {
     123                 :             :     // In C++20, use std::format() for this
     124                 :           2 :     std::string_view format_string{messages[id]};
     125                 :           2 :     std::stringstream message;
     126                 :             : 
     127                 :           2 :     size_t pos = 0;
     128                 :           2 :     size_t copied = 0;
     129                 :           2 :     size_t args_ptr = 0;
     130                 :           2 :     size_t nargs_given = args.size();
     131                 :             : 
     132         [ +  + ]:           6 :     while ((pos = format_string.find("{}", pos)) != std::string::npos) {
     133         [ -  + ]:           4 :         if (args_ptr >= nargs_given) {
     134                 :           0 :             g_critical("Only %zu format args passed for message ID %u",
     135                 :             :                        nargs_given, unsigned{id});
     136                 :           0 :             return;
     137                 :             :         }
     138                 :             : 
     139                 :           4 :         message << format_string.substr(copied, pos - copied);
     140                 :           4 :         message << args[args_ptr++];
     141                 :           4 :         pos = copied = pos + 2;  // skip over braces
     142                 :             :     }
     143         [ -  + ]:           2 :     if (args_ptr != nargs_given) {
     144                 :           0 :         g_critical("Excess %zu format args passed for message ID %u",
     145                 :             :                    nargs_given, unsigned{id});
     146                 :           0 :         return;
     147                 :             :     }
     148                 :             : 
     149                 :           2 :     message << format_string.substr(copied, std::string::npos);
     150                 :             : 
     151                 :           2 :     std::string message_formatted = message.str();
     152                 :           2 :     warn_deprecated_unsafe_internal(cx, id, message_formatted.c_str());
     153         [ +  - ]:           2 : }
        

Generated by: LCOV version 2.0-1