Bug 1414096 - Remove support for nsISupportsString values in nsPrefBranch::{get,set}ComplexValue(). r=florian.
☠☠ backed out by b69cb7c76bcd ☠ ☠
authorNicholas Nethercote <nnethercote@mozilla.com>
Tue, 31 Oct 2017 16:34:35 +1100
changeset 443866 e843de356b7e5f3cb01f114bc101f4a71092550b
parent 443865 e195ac70ab165bd6806d0bffc3db25fcdd708c51
child 443867 23f86a1ac424051004163f370b80d7b7bc5a35dd
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersflorian
bugs1414096, 1345294
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1414096 - Remove support for nsISupportsString values in nsPrefBranch::{get,set}ComplexValue(). r=florian. Bug 1345294 introduced nsPrefBranch::{get,set}StringPref(), which allowed the getting of utf8 strings from prefs, which previously required using nsISupportsString with {get,set}ComplexValue. That bug also converted most uses. This patch finishes the job. - It removes the nsISupportsString support. - It converts existing code that relied on the nsISupportsString. - It removes the lint that was set up to detect such uses of nsISupportsString.
mobile/android/chrome/content/about.js
modules/libpref/Preferences.cpp
modules/libpref/nsIPrefBranch.idl
modules/libpref/test/unit/test_defaultValues.js
modules/libpref/test/unit/test_libPrefs.js
netwerk/dns/nsIDNService.cpp
testing/marionette/client/marionette_driver/marionette.py
toolkit/content/tests/chrome/test_preferences.xul
toolkit/modules/Preferences.jsm
toolkit/modules/Troubleshoot.jsm
toolkit/modules/tests/xpcshell/test_Preferences.js
tools/lint/docs/linters/eslint-plugin-mozilla.rst
tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js
tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
tools/lint/eslint/eslint-plugin-mozilla/lib/rules/avoid-nsISupportsString-preferences.js
tools/lint/eslint/eslint-plugin-mozilla/package.json
tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-nsISupportsString-preferences.js
--- a/mobile/android/chrome/content/about.js
+++ b/mobile/android/chrome/content/about.js
@@ -25,17 +25,17 @@ function init() {
   try {
     let distroId = Services.prefs.getCharPref("distribution.id");
     if (distroId) {
       let distroVersion = Services.prefs.getCharPref("distribution.version");
       let distroIdField = document.getElementById("distributionID");
       distroIdField.textContent = distroId + " - " + distroVersion;
       distroIdField.hidden = false;
 
-      let distroAbout = Services.prefs.getComplexValue("distribution.about", Ci.nsISupportsString);
+      let distroAbout = Services.prefs.getStringPref("distribution.about");
       let distroField = document.getElementById("distributionAbout");
       distroField.textContent = distroAbout;
       distroField.hidden = false;
     }
   } catch (e) {
     // Pref is unset
   }
 
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -2526,30 +2526,16 @@ nsPrefBranch::GetComplexValue(const char
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     relativePref.forget(reinterpret_cast<nsIRelativeFilePref**>(aRetVal));
     return NS_OK;
   }
 
-  if (aType.Equals(NS_GET_IID(nsISupportsString))) {
-    nsCOMPtr<nsISupportsString> theString(
-      do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
-
-    if (NS_SUCCEEDED(rv)) {
-      // Debugging to see why we end up with very long strings here with
-      // some addons, see bug 836263.
-      NS_ConvertUTF8toUTF16 wdata(utf8String);
-      theString->SetData(wdata);
-      theString.forget(reinterpret_cast<nsISupportsString**>(aRetVal));
-    }
-    return rv;
-  }
-
   NS_WARNING("nsPrefBranch::GetComplexValue - Unsupported interface type");
   return NS_NOINTERFACE;
 }
 
 nsresult
 nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName,
                                         const nsAString& aValue)
 {
@@ -2671,18 +2657,17 @@ nsPrefBranch::SetComplexValue(const char
     nsAutoCString descriptorString;
     descriptorString.Append('[');
     descriptorString.Append(relativeToKey);
     descriptorString.Append(']');
     descriptorString.Append(relDescriptor);
     return SetCharPrefInternal(aPrefName, descriptorString);
   }
 
-  if (aType.Equals(NS_GET_IID(nsISupportsString)) ||
-      aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
+  if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
     nsCOMPtr<nsISupportsString> theString = do_QueryInterface(aValue);
 
     if (theString) {
       nsString wideString;
 
       rv = theString->GetData(wideString);
       if (NS_SUCCEEDED(rv)) {
         // Check sanity of string length before any lengthy conversion
--- a/modules/libpref/nsIPrefBranch.idl
+++ b/modules/libpref/nsIPrefBranch.idl
@@ -186,18 +186,16 @@ interface nsIPrefBranch : nsISupports
    * Called to get the state of an individual complex preference. A complex
    * preference is a preference which represents an XPCOM object that can not
    * be easily represented using a standard boolean, integer or string value.
    *
    * @param aPrefName The complex preference to get the value of.
    * @param aType     The XPCOM interface that this complex preference
    *                  represents. Interfaces currently supported are:
    *                    - nsIFile
-   *                    - nsISupportsString (UniChar)
-   *                      (deprecated; see getStringPref)
    *                    - nsIPrefLocalizedString (Localized UniChar)
    * @param aValue    The XPCOM object into which to the complex preference 
    *                  value should be retrieved.
    *
    * @throws Error The value does not exist or is the wrong type.
    *
    * @see setComplexValue
    */
--- a/modules/libpref/test/unit/test_defaultValues.js
+++ b/modules/libpref/test/unit/test_defaultValues.js
@@ -31,23 +31,16 @@ function run_test() {
   prefName = "test.default.values.string";
   do_check_throws(function() { ps.getCharPref(prefName); },
                   Cr.NS_ERROR_UNEXPECTED);
   strictEqual(ps.getStringPref(prefName, ""), "");
   strictEqual(ps.getStringPref(prefName, "éèçàê€"), "éèçàê€");
   ps.setStringPref(prefName, "éèçàê€");
   strictEqual(ps.getStringPref(prefName), "éèçàê€");
   strictEqual(ps.getStringPref(prefName, "string"), "éèçàê€");
-  strictEqual(ps.getStringPref(prefName),
-              ps.getComplexValue(prefName, Ci.nsISupportsString).data);
-  let str = Cc["@mozilla.org/supports-string;1"].
-              createInstance(Ci.nsISupportsString);
-  str.data = "ù€ÚîœïŒëøÇ“";
-  ps.setComplexValue(prefName, Ci.nsISupportsString, str);
-  strictEqual(ps.getStringPref(prefName), "ù€ÚîœïŒëøÇ“");
 
   prefName = "test.default.values.float";
   do_check_throws(function() { ps.getFloatPref(prefName); },
                   Cr.NS_ERROR_UNEXPECTED);
   strictEqual(ps.getFloatPref(prefName, 3.5), 3.5);
   strictEqual(ps.getFloatPref(prefName, 0), 0);
   ps.setCharPref(prefName, 1.75);
   strictEqual(ps.getFloatPref(prefName), 1.75);
--- a/modules/libpref/test/unit/test_libPrefs.js
+++ b/modules/libpref/test/unit/test_libPrefs.js
@@ -43,19 +43,19 @@ function run_test() {
     pb.getIntPref(null); },  Cr.NS_ERROR_INVALID_ARG);
   do_check_throws(function() {
     pb.setIntPref(null, 0); },  Cr.NS_ERROR_INVALID_ARG);
   do_check_throws(function() {
     pb.getCharPref(null); },  Cr.NS_ERROR_INVALID_ARG);
   do_check_throws(function() {
     pb.setCharPref(null, null); },  Cr.NS_ERROR_INVALID_ARG);
   do_check_throws(function() {
-    pb.getComplexValue(null, Components.interfaces.nsISupportsString); },  Cr.NS_ERROR_INVALID_ARG);
+    pb.getStringPref(null); },  Cr.NS_ERROR_INVALID_ARG);
   do_check_throws(function() {
-    pb.setComplexValue(null, Components.interfaces.nsISupportsString, pb); },  Cr.NS_ERROR_INVALID_ARG);
+    pb.setStringPref(null, null); },  Cr.NS_ERROR_INVALID_ARG);
   do_check_throws(function() {
     pb.clearUserPref(null); },  Cr.NS_ERROR_INVALID_ARG);
   do_check_throws(function() {
     pb.prefHasUserValue(null); },  Cr.NS_ERROR_INVALID_ARG);
   do_check_throws(function() {
     pb.lockPref(null); },  Cr.NS_ERROR_INVALID_ARG);
   do_check_throws(function() {
     pb.prefIsLocked(null); },  Cr.NS_ERROR_INVALID_ARG);
--- a/netwerk/dns/nsIDNService.cpp
+++ b/netwerk/dns/nsIDNService.cpp
@@ -97,24 +97,24 @@ NS_IMETHODIMP nsIDNService::Observe(nsIS
 }
 
 void nsIDNService::prefsChanged(nsIPrefBranch *prefBranch, const char16_t *pref)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mLock.AssertCurrentThreadOwns();
 
   if (!pref || NS_LITERAL_STRING(NS_NET_PREF_IDNBLACKLIST).Equals(pref)) {
-    nsCOMPtr<nsISupportsString> blacklist;
-    nsresult rv = prefBranch->GetComplexValue(NS_NET_PREF_IDNBLACKLIST,
-                                              NS_GET_IID(nsISupportsString),
-                                              getter_AddRefs(blacklist));
-    if (NS_SUCCEEDED(rv))
-      blacklist->ToString(getter_Copies(mIDNBlacklist));
-    else
+    nsAutoCString blacklist;
+    nsresult rv =
+      prefBranch->GetStringPref(NS_NET_PREF_IDNBLACKLIST, EmptyCString(), 0, blacklist);
+    if (NS_SUCCEEDED(rv)) {
+      CopyUTF8toUTF16(blacklist, mIDNBlacklist);
+    } else {
       mIDNBlacklist.Truncate();
+    }
   }
   if (!pref || NS_LITERAL_STRING(NS_NET_PREF_SHOWPUNYCODE).Equals(pref)) {
     bool val;
     if (NS_SUCCEEDED(prefBranch->GetBoolPref(NS_NET_PREF_SHOWPUNYCODE, &val)))
       mShowPunycode = val;
   }
   if (!pref || NS_LITERAL_STRING(NS_NET_PREF_IDNUSEWHITELIST).Equals(pref)) {
     bool val;
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -863,26 +863,26 @@ class Marionette(object):
         :param pref: Name of the preference.
         """
         with self.using_context(self.CONTEXT_CHROME):
             self.execute_script("""
                Components.utils.import("resource://gre/modules/Preferences.jsm");
                Preferences.reset(arguments[0]);
                """, script_args=(pref,))
 
-    def get_pref(self, pref, default_branch=False, value_type="nsISupportsString"):
+    def get_pref(self, pref, default_branch=False, value_type="unspecified"):
         """Get the value of the specified preference.
 
         :param pref: Name of the preference.
         :param default_branch: Optional, if `True` the preference value will be read
                                from the default branch. Otherwise the user-defined
                                value if set is returned. Defaults to `False`.
         :param value_type: Optional, XPCOM interface of the pref's complex value.
-                           Defaults to `nsISupportsString`. Other possible values are:
-                           `nsIFile`, and `nsIPrefLocalizedString`.
+                           Possible values are: `nsIFile` and
+                           `nsIPrefLocalizedString`.
 
         Usage example::
 
             marionette.get_pref("browser.tabs.warnOnClose")
 
         """
         with self.using_context(self.CONTEXT_CHROME):
             pref_value = self.execute_script("""
--- a/toolkit/content/tests/chrome/test_preferences.xul
+++ b/toolkit/content/tests/chrome/test_preferences.xul
@@ -17,50 +17,44 @@
                             .getService(Components.interfaces.nsIPrefBranch);
 
     // preference values, set 1
     const kPrefValueSet1 =
     {
         int:          23,
         bool:         true,
         string:       "rheeet!",
+        unichar:      "äöüßÄÖÜ",
         wstring_data: "日本語",
-        unichar_data: "äöüßÄÖÜ",
         file_data:    "/",
 
         wstring: Components.classes["@mozilla.org/pref-localizedstring;1"]
                            .createInstance(Components.interfaces.nsIPrefLocalizedString),
-        unichar: Components.classes["@mozilla.org/supports-string;1"]
-                           .createInstance(Components.interfaces.nsISupportsString),
         file:    Components.classes["@mozilla.org/file/local;1"]
                            .createInstance(Components.interfaces.nsIFile)
     };
     kPrefValueSet1.wstring.data = kPrefValueSet1.wstring_data;
-    kPrefValueSet1.unichar.data = kPrefValueSet1.unichar_data;
     SafeFileInit(kPrefValueSet1.file, kPrefValueSet1.file_data);
 
     // preference values, set 2
     const kPrefValueSet2 =
     {
         int:          42,
         bool:         false,
         string:       "Mozilla",
+        unichar:      "áôùšŽ",
         wstring_data: "헤드라인A",
-        unichar_data: "áôùšŽ",
         file_data:    "/home",
 
         wstring: Components.classes["@mozilla.org/pref-localizedstring;1"]
                            .createInstance(Components.interfaces.nsIPrefLocalizedString),
-        unichar: Components.classes["@mozilla.org/supports-string;1"]
-                           .createInstance(Components.interfaces.nsISupportsString),
         file:    Components.classes["@mozilla.org/file/local;1"]
                            .createInstance(Components.interfaces.nsIFile)
     };
     kPrefValueSet2.wstring.data = kPrefValueSet2.wstring_data;
-    kPrefValueSet2.unichar.data = kPrefValueSet2.unichar_data;
     SafeFileInit(kPrefValueSet2.file, kPrefValueSet2.file_data);
 
 
     function SafeFileInit(aFile, aPath)
     {
       // set file path without dying for exceptions
       try
       {
@@ -71,62 +65,57 @@
 
     function CreateEmptyPrefValueSet()
     {
       var result =
       {
         int:          undefined,
         bool:         undefined,
         string:       undefined,
+        unichar:      undefined,
         wstring_data: undefined,
-        unichar_data: undefined,
         file_data:    undefined,
         wstring:      undefined,
-        unichar:      undefined,
         file:         undefined
       };
       return result;
     }
 
     function WritePrefsToSystem(aPrefValueSet)
     {
       // write preference data via XPCOM
       kPref.setIntPref ("tests.static_preference_int",    aPrefValueSet.int);
       kPref.setBoolPref("tests.static_preference_bool",   aPrefValueSet.bool);
       kPref.setCharPref("tests.static_preference_string", aPrefValueSet.string);
+      kPref.setStringPref("tests.static_preference_unichar", aPrefValueSet.unichar);
       kPref.setComplexValue("tests.static_preference_wstring",
                             Components.interfaces.nsIPrefLocalizedString,
                             aPrefValueSet.wstring);
-      kPref.setComplexValue("tests.static_preference_unichar",
-                            Components.interfaces.nsISupportsString,
-                            aPrefValueSet.unichar);
       kPref.setComplexValue("tests.static_preference_file",
                             Components.interfaces.nsIFile,
                             aPrefValueSet.file);
     }
 
     function ReadPrefsFromSystem()
     {
       // read preference data via XPCOM
       var result = CreateEmptyPrefValueSet();
       try {result.int    = kPref.getIntPref ("tests.static_preference_int")   } catch (ignored) {};
       try {result.bool   = kPref.getBoolPref("tests.static_preference_bool")  } catch (ignored) {};
       try {result.string = kPref.getCharPref("tests.static_preference_string")} catch (ignored) {};
       try
       {
-        result.wstring = kPref.getComplexValue("tests.static_preference_wstring",
-                                               Components.interfaces.nsIPrefLocalizedString);
-        result.wstring_data = result.wstring.data;
+        result.unichar = kPref.getStringPref("tests.static_preference_unichar");
       }
       catch (ignored) {};
       try
       {
-        result.unichar = kPref.getComplexValue("tests.static_preference_unichar",
-                                               Components.interfaces.nsISupportsString);
-        result.unichar_data = result.unichar.data;
+        result.wstring = kPref.getComplexValue("tests.static_preference_wstring",
+                                               Components.interfaces.nsIPrefLocalizedString);
+        result.wstring_data = result.wstring.data;
       }
       catch (ignored) {};
       try
       {
         result.file = kPref.getComplexValue("tests.static_preference_file",
                                             Components.interfaces.nsIFile);
         result.file_data    = result.file.data;
       }
@@ -140,177 +129,170 @@
     }
 
     function WritePrefsToPreferences(aPrefWindow, aPrefValueSet)
     {
       // write preference data into <preference>s
       GetXULElement(aPrefWindow, "tests.static_preference_int"    ).value = aPrefValueSet.int;
       GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).value = aPrefValueSet.bool;
       GetXULElement(aPrefWindow, "tests.static_preference_string" ).value = aPrefValueSet.string;
+      GetXULElement(aPrefWindow, "tests.static_preference_unichar").value = aPrefValueSet.unichar;
       GetXULElement(aPrefWindow, "tests.static_preference_wstring").value = aPrefValueSet.wstring_data;
-      GetXULElement(aPrefWindow, "tests.static_preference_unichar").value = aPrefValueSet.unichar_data;
       GetXULElement(aPrefWindow, "tests.static_preference_file"   ).value = aPrefValueSet.file_data;
     }
 
     function ReadPrefsFromPreferences(aPrefWindow)
     {
       // read preference data from <preference>s
       var result =
       {
         int:          GetXULElement(aPrefWindow, "tests.static_preference_int"    ).value,
         bool:         GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).value,
         string:       GetXULElement(aPrefWindow, "tests.static_preference_string" ).value,
+        unichar:      GetXULElement(aPrefWindow, "tests.static_preference_unichar").value,
         wstring_data: GetXULElement(aPrefWindow, "tests.static_preference_wstring").value,
-        unichar_data: GetXULElement(aPrefWindow, "tests.static_preference_unichar").value,
         file_data:    GetXULElement(aPrefWindow, "tests.static_preference_file"   ).value,
         wstring: Components.classes["@mozilla.org/pref-localizedstring;1"]
                            .createInstance(Components.interfaces.nsIPrefLocalizedString),
-        unichar: Components.classes["@mozilla.org/supports-string;1"]
-                           .createInstance(Components.interfaces.nsISupportsString),
         file:    Components.classes["@mozilla.org/file/local;1"]
                            .createInstance(Components.interfaces.nsIFile)
       }
       result.wstring.data = result.wstring_data;
-      result.unichar.data = result.unichar_data;
       SafeFileInit(result.file, result.file_data);
       return result;
     }
 
     function WritePrefsToUI(aPrefWindow, aPrefValueSet)
     {
       // write preference data into UI elements
       GetXULElement(aPrefWindow, "static_element_int"    ).value   = aPrefValueSet.int;
       GetXULElement(aPrefWindow, "static_element_bool"   ).checked = aPrefValueSet.bool;
       GetXULElement(aPrefWindow, "static_element_string" ).value   = aPrefValueSet.string;
+      GetXULElement(aPrefWindow, "static_element_unichar").value   = aPrefValueSet.unichar;
       GetXULElement(aPrefWindow, "static_element_wstring").value   = aPrefValueSet.wstring_data;
-      GetXULElement(aPrefWindow, "static_element_unichar").value   = aPrefValueSet.unichar_data;
       GetXULElement(aPrefWindow, "static_element_file"   ).value   = aPrefValueSet.file_data;
     }
 
     function ReadPrefsFromUI(aPrefWindow)
     {
       // read preference data from <preference>s
       var result =
       {
         int:          GetXULElement(aPrefWindow, "static_element_int"    ).value,
         bool:         GetXULElement(aPrefWindow, "static_element_bool"   ).checked,
         string:       GetXULElement(aPrefWindow, "static_element_string" ).value,
+        unichar:      GetXULElement(aPrefWindow, "static_element_unichar").value,
         wstring_data: GetXULElement(aPrefWindow, "static_element_wstring").value,
-        unichar_data: GetXULElement(aPrefWindow, "static_element_unichar").value,
         file_data:    GetXULElement(aPrefWindow, "static_element_file"   ).value,
         wstring: Components.classes["@mozilla.org/pref-localizedstring;1"]
                            .createInstance(Components.interfaces.nsIPrefLocalizedString),
-        unichar: Components.classes["@mozilla.org/supports-string;1"]
-                           .createInstance(Components.interfaces.nsISupportsString),
         file:    Components.classes["@mozilla.org/file/local;1"]
                            .createInstance(Components.interfaces.nsIFile)
       }
       result.wstring.data = result.wstring_data;
-      result.unichar.data = result.unichar_data;
       SafeFileInit(result.file, result.file_data);
       return result;
     }
 
 
     function RunInstantPrefTest(aPrefWindow)
     {
       // remark: there's currently no UI element binding for files
 
       // were all <preferences> correctly initialized?
       var expected = kPrefValueSet1;
       var found    = ReadPrefsFromPreferences(aPrefWindow);
       ok(found.int          === expected.int,          "instant pref init int"    );
       ok(found.bool         === expected.bool,         "instant pref init bool"   );
       ok(found.string       === expected.string,       "instant pref init string" );
+      ok(found.unichar      === expected.unichar,      "instant pref init unichar");
       ok(found.wstring_data === expected.wstring_data, "instant pref init wstring");
-      ok(found.unichar_data === expected.unichar_data, "instant pref init unichar");
       todo(found.file_data  === expected.file_data,    "instant pref init file"   );
 
       // were all elements correctly initialized? (loose check)
       found = ReadPrefsFromUI(aPrefWindow);
       ok(found.int          == expected.int,          "instant element init int"    );
       ok(found.bool         == expected.bool,         "instant element init bool"   );
       ok(found.string       == expected.string,       "instant element init string" );
+      ok(found.unichar      == expected.unichar,      "instant element init unichar");
       ok(found.wstring_data == expected.wstring_data, "instant element init wstring");
-      ok(found.unichar_data == expected.unichar_data, "instant element init unichar");
       todo(found.file_data  == expected.file_data,    "instant element init file"   );
 
       // do some changes in the UI
       expected = kPrefValueSet2;
       WritePrefsToUI(aPrefWindow, expected);
 
       // UI changes should get passed to the <preference>s,
       // but currently they aren't if the changes are made programmatically
       // (the handlers preference.change/prefpane.input and prefpane.change
       //  are called for manual changes, though).
       found = ReadPrefsFromPreferences(aPrefWindow);
       todo(found.int          === expected.int,          "instant change pref int"    );
       todo(found.bool         === expected.bool,         "instant change pref bool"   );
       todo(found.string       === expected.string,       "instant change pref string" );
+      todo(found.unichar      === expected.unichar,      "instant change pref unichar");
       todo(found.wstring_data === expected.wstring_data, "instant change pref wstring");
-      todo(found.unichar_data === expected.unichar_data, "instant change pref unichar");
       todo(found.file_data    === expected.file_data,    "instant change pref file"   );
 
       // and these changes should get passed to the system instantly
       // (which obviously can't pass with the above failing)
       found = ReadPrefsFromSystem();
       todo(found.int          === expected.int,          "instant change element int"    );
       todo(found.bool         === expected.bool,         "instant change element bool"   );
       todo(found.string       === expected.string,       "instant change element string" );
+      todo(found.unichar      === expected.unichar,      "instant change element unichar");
       todo(found.wstring_data === expected.wstring_data, "instant change element wstring");
-      todo(found.unichar_data === expected.unichar_data, "instant change element unichar");
       todo(found.file_data    === expected.file_data,    "instant change element file"   );
 
       // try resetting the prefs to default values (which should be empty here)
       GetXULElement(aPrefWindow, "tests.static_preference_int"    ).reset();
       GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).reset();
       GetXULElement(aPrefWindow, "tests.static_preference_string" ).reset();
+      GetXULElement(aPrefWindow, "tests.static_preference_unichar").reset();
       GetXULElement(aPrefWindow, "tests.static_preference_wstring").reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_unichar").reset();
       GetXULElement(aPrefWindow, "tests.static_preference_file"   ).reset();
 
       // check system
       expected = CreateEmptyPrefValueSet();
       found    = ReadPrefsFromSystem();
       ok(found.int          === expected.int,          "instant reset system int"    );
       ok(found.bool         === expected.bool,         "instant reset system bool"   );
       ok(found.string       === expected.string,       "instant reset system string" );
+      ok(found.unichar      === expected.unichar,      "instant reset system unichar");
       ok(found.wstring_data === expected.wstring_data, "instant reset system wstring");
-      ok(found.unichar_data === expected.unichar_data, "instant reset system unichar");
       ok(found.file_data    === expected.file_data,    "instant reset system file"   );
 
       // check UI
       expected =
       {
         // alas, we don't have XUL elements with typeof(value) == int :(
         // int:         0,
         int:          "",
         bool:         false,
         string:       "",
+        unichar:      "",
         wstring_data: "",
-        unichar_data: "",
         file_data:    "",
         wstring:      {},
-        unichar:      {},
         file:         {}
       };
       found = ReadPrefsFromUI(aPrefWindow);
       ok(found.int          === expected.int,          "instant reset element int"    );
       ok(found.bool         === expected.bool,         "instant reset element bool"   );
       ok(found.string       === expected.string,       "instant reset element string" );
+      ok(found.unichar      === expected.unichar,      "instant reset element unichar");
       ok(found.wstring_data === expected.wstring_data, "instant reset element wstring");
-      ok(found.unichar_data === expected.unichar_data, "instant reset element unichar");
 //      ok(found.file_data    === expected.file_data,    "instant reset element file"   );
 
       // check hasUserValue
       ok(GetXULElement(aPrefWindow, "tests.static_preference_int"    ).hasUserValue === false, "instant reset hasUserValue int"    );
       ok(GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).hasUserValue === false, "instant reset hasUserValue bool"   );
       ok(GetXULElement(aPrefWindow, "tests.static_preference_string" ).hasUserValue === false, "instant reset hasUserValue string" );
+      ok(GetXULElement(aPrefWindow, "tests.static_preference_unichar").hasUserValue === false, "instant reset hasUserValue unichar");
       ok(GetXULElement(aPrefWindow, "tests.static_preference_wstring").hasUserValue === false, "instant reset hasUserValue wstring");
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_unichar").hasUserValue === false, "instant reset hasUserValue unichar");
       ok(GetXULElement(aPrefWindow, "tests.static_preference_file"   ).hasUserValue === false, "instant reset hasUserValue file"   );
 
       // done with instant apply checks
     }
 
     function RunNonInstantPrefTestGeneral(aPrefWindow)
     {
       // Non-instant apply tests are harder: not only do we need to check that
@@ -320,103 +302,102 @@
       // remark: there's currently no UI element binding for files
 
       // were all <preferences> correctly initialized?
       var expected = kPrefValueSet1;
       var found    = ReadPrefsFromPreferences(aPrefWindow);
       ok(found.int          === expected.int,          "non-instant pref init int"    );
       ok(found.bool         === expected.bool,         "non-instant pref init bool"   );
       ok(found.string       === expected.string,       "non-instant pref init string" );
+      ok(found.unichar      === expected.unichar,      "non-instant pref init unichar");
       ok(found.wstring_data === expected.wstring_data, "non-instant pref init wstring");
-      ok(found.unichar_data === expected.unichar_data, "non-instant pref init unichar");
       todo(found.file_data  === expected.file_data,    "non-instant pref init file"   );
 
       // were all elements correctly initialized? (loose check)
       found = ReadPrefsFromUI(aPrefWindow);
       ok(found.int          == expected.int,          "non-instant element init int"    );
       ok(found.bool         == expected.bool,         "non-instant element init bool"   );
       ok(found.string       == expected.string,       "non-instant element init string" );
+      ok(found.unichar      == expected.unichar,      "non-instant element init unichar");
       ok(found.wstring_data == expected.wstring_data, "non-instant element init wstring");
-      ok(found.unichar_data == expected.unichar_data, "non-instant element init unichar");
       todo(found.file_data  == expected.file_data,    "non-instant element init file"   );
 
       // do some changes in the UI
       expected = kPrefValueSet2;
       WritePrefsToUI(aPrefWindow, expected);
 
       // UI changes should get passed to the <preference>s,
       // but currently they aren't if the changes are made programmatically
       // (the handlers preference.change/prefpane.input and prefpane.change
       //  are called for manual changes, though).
       found = ReadPrefsFromPreferences(aPrefWindow);
       todo(found.int          === expected.int,          "non-instant change pref int"    );
       todo(found.bool         === expected.bool,         "non-instant change pref bool"   );
       todo(found.string       === expected.string,       "non-instant change pref string" );
+      todo(found.unichar      === expected.unichar,      "non-instant change pref unichar");
       todo(found.wstring_data === expected.wstring_data, "non-instant change pref wstring");
-      todo(found.unichar_data === expected.unichar_data, "non-instant change pref unichar");
       todo(found.file_data    === expected.file_data,    "non-instant change pref file"   );
 
       // and these changes should *NOT* get passed to the system
       // (which obviously always passes with the above failing)
       expected = kPrefValueSet1;
       found    = ReadPrefsFromSystem();
       ok(found.int          === expected.int,          "non-instant change element int"    );
       ok(found.bool         === expected.bool,         "non-instant change element bool"   );
       ok(found.string       === expected.string,       "non-instant change element string" );
+      ok(found.unichar      === expected.unichar,      "non-instant change element unichar");
       ok(found.wstring_data === expected.wstring_data, "non-instant change element wstring");
-      ok(found.unichar_data === expected.unichar_data, "non-instant change element unichar");
       todo(found.file_data  === expected.file_data,    "non-instant change element file"   );
 
       // try resetting the prefs to default values (which should be empty here)
       GetXULElement(aPrefWindow, "tests.static_preference_int"    ).reset();
       GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).reset();
       GetXULElement(aPrefWindow, "tests.static_preference_string" ).reset();
+      GetXULElement(aPrefWindow, "tests.static_preference_unichar").reset();
       GetXULElement(aPrefWindow, "tests.static_preference_wstring").reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_unichar").reset();
       GetXULElement(aPrefWindow, "tests.static_preference_file"   ).reset();
 
       // check system: the current values *MUST NOT* change
       expected = kPrefValueSet1;
       found    = ReadPrefsFromSystem();
       ok(found.int          === expected.int,          "non-instant reset system int"    );
       ok(found.bool         === expected.bool,         "non-instant reset system bool"   );
       ok(found.string       === expected.string,       "non-instant reset system string" );
+      ok(found.unichar      === expected.unichar,      "non-instant reset system unichar");
       ok(found.wstring_data === expected.wstring_data, "non-instant reset system wstring");
-      ok(found.unichar_data === expected.unichar_data, "non-instant reset system unichar");
       todo(found.file_data  === expected.file_data,    "non-instant reset system file"   );
 
       // check UI: these values should be reset
       expected =
       {
         // alas, we don't have XUL elements with typeof(value) == int :(
         // int:         0,
         int:          "",
         bool:         false,
         string:       "",
+        unichar:      "",
         wstring_data: "",
-        unichar_data: "",
         file_data:    "",
         wstring:      {},
-        unichar:      {},
         file:         {}
       };
       found = ReadPrefsFromUI(aPrefWindow);
       ok(found.int          === expected.int,          "non-instant reset element int"    );
       ok(found.bool         === expected.bool,         "non-instant reset element bool"   );
       ok(found.string       === expected.string,       "non-instant reset element string" );
+      ok(found.unichar      === expected.unichar,      "non-instant reset element unichar");
       ok(found.wstring_data === expected.wstring_data, "non-instant reset element wstring");
-      ok(found.unichar_data === expected.unichar_data, "non-instant reset element unichar");
 //      ok(found.file_data    === expected.file_data,    "non-instant reset element file"   );
 
       // check hasUserValue
       ok(GetXULElement(aPrefWindow, "tests.static_preference_int"    ).hasUserValue === false, "non-instant reset hasUserValue int"    );
       ok(GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).hasUserValue === false, "non-instant reset hasUserValue bool"   );
       ok(GetXULElement(aPrefWindow, "tests.static_preference_string" ).hasUserValue === false, "non-instant reset hasUserValue string" );
+      ok(GetXULElement(aPrefWindow, "tests.static_preference_unichar").hasUserValue === false, "non-instant reset hasUserValue unichar");
       ok(GetXULElement(aPrefWindow, "tests.static_preference_wstring").hasUserValue === false, "non-instant reset hasUserValue wstring");
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_unichar").hasUserValue === false, "non-instant reset hasUserValue unichar");
       ok(GetXULElement(aPrefWindow, "tests.static_preference_file"   ).hasUserValue === false, "non-instant reset hasUserValue file"   );
     }
 
     function RunNonInstantPrefTestClose(aPrefWindow)
     {
       WritePrefsToPreferences(aPrefWindow, kPrefValueSet2);
     }
 
@@ -429,18 +410,18 @@
     }
 
     function RunResetPrefTest(aPrefWindow)
     {
       // try resetting the prefs to default values
       GetXULElement(aPrefWindow, "tests.static_preference_int"    ).reset();
       GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).reset();
       GetXULElement(aPrefWindow, "tests.static_preference_string" ).reset();
+      GetXULElement(aPrefWindow, "tests.static_preference_unichar").reset();
       GetXULElement(aPrefWindow, "tests.static_preference_wstring").reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_unichar").reset();
       GetXULElement(aPrefWindow, "tests.static_preference_file"   ).reset();
     }
 
     function InitTestPrefs(aInstantApply)
     {
       // set instant apply mode and init prefs to set 1
       kPref.setBoolPref("browser.preferences.instantApply", aInstantApply);
       WritePrefsToSystem(kPrefValueSet1);
@@ -455,18 +436,18 @@
       // - test deferred reset in child window
       InitTestPrefs(true);
       openDialog("window_preferences2.xul", "", "modal", RunResetPrefTest, false);
       expected = kPrefValueSet1;
       found    = ReadPrefsFromSystem();
       ok(found.int          === expected.int,          "instant reset deferred int"    );
       ok(found.bool         === expected.bool,         "instant reset deferred bool"   );
       ok(found.string       === expected.string,       "instant reset deferred string" );
+      ok(found.unichar      === expected.unichar,      "instant reset deferred unichar");
       ok(found.wstring_data === expected.wstring_data, "instant reset deferred wstring");
-      ok(found.unichar_data === expected.unichar_data, "instant reset deferred unichar");
       todo(found.file_data  === expected.file_data,    "instant reset deferred file"   );
     }
 
     function RunTestNonInstant()
     {
       // test without instantApply
       // - general tests, similar to instant apply
       InitTestPrefs(false);
@@ -475,42 +456,42 @@
       // - test Cancel
       InitTestPrefs(false);
       openDialog("window_preferences.xul", "", "modal", RunNonInstantPrefTestClose, false);
       var expected = kPrefValueSet1;
       var found    = ReadPrefsFromSystem();
       ok(found.int          === expected.int,          "non-instant cancel system int"    );
       ok(found.bool         === expected.bool,         "non-instant cancel system bool"   );
       ok(found.string       === expected.string,       "non-instant cancel system string" );
+      ok(found.unichar      === expected.unichar,      "non-instant cancel system unichar");
       ok(found.wstring_data === expected.wstring_data, "non-instant cancel system wstring");
-      ok(found.unichar_data === expected.unichar_data, "non-instant cancel system unichar");
       todo(found.file_data  === expected.file_data,    "non-instant cancel system file"   );
       
       // - test Accept
       InitTestPrefs(false);
       openDialog("window_preferences.xul", "", "modal", RunNonInstantPrefTestClose, true);
       expected = kPrefValueSet2;
       found    = ReadPrefsFromSystem();
       ok(found.int          === expected.int,          "non-instant accept system int"    );
       ok(found.bool         === expected.bool,         "non-instant accept system bool"   );
       ok(found.string       === expected.string,       "non-instant accept system string" );
+      ok(found.unichar      === expected.unichar,      "non-instant accept system unichar");
       ok(found.wstring_data === expected.wstring_data, "non-instant accept system wstring");
-      ok(found.unichar_data === expected.unichar_data, "non-instant accept system unichar");
       todo(found.file_data  === expected.file_data,    "non-instant accept system file"   );
 
       // - test deferred reset in child window
       InitTestPrefs(false);
       openDialog("window_preferences2.xul", "", "modal", RunResetPrefTest, true);
       expected = CreateEmptyPrefValueSet();
       found    = ReadPrefsFromSystem();
       ok(found.int          === expected.int,          "non-instant reset deferred int"    );
       ok(found.bool         === expected.bool,         "non-instant reset deferred bool"   );
       ok(found.string       === expected.string,       "non-instant reset deferred string" );
+      ok(found.unichar      === expected.unichar,      "non-instant reset deferred unichar");
       ok(found.wstring_data === expected.wstring_data, "non-instant reset deferred wstring");
-      ok(found.unichar_data === expected.unichar_data, "non-instant reset deferred unichar");
       ok(found.file_data    === expected.file_data,    "non-instant reset deferred file"   );
     }
 
     function RunTestCommandRedirect()
     {
       openDialog("window_preferences_commandretarget.xul", "", "modal", RunCheckCommandRedirect, true);
     }
 
--- a/toolkit/modules/Preferences.jsm
+++ b/toolkit/modules/Preferences.jsm
@@ -42,27 +42,33 @@ this.Preferences =
  * @param   defaultValue
  *          the default value, if any, for prefs that don't have one
  *
  * @param   valueType
  *          the XPCOM interface of the pref's complex value type, if any
  *
  * @returns the value of the pref, if any; otherwise the default value
  */
-Preferences.get = function(prefName, defaultValue, valueType = Ci.nsISupportsString) {
+Preferences.get = function(prefName, defaultValue, valueType = null) {
   if (Array.isArray(prefName))
     return prefName.map(v => this.get(v, defaultValue));
 
   return this._get(prefName, defaultValue, valueType);
 };
 
 Preferences._get = function(prefName, defaultValue, valueType) {
   switch (this._prefBranch.getPrefType(prefName)) {
     case Ci.nsIPrefBranch.PREF_STRING:
-      return this._prefBranch.getComplexValue(prefName, valueType).data;
+      if (valueType) {
+        let ifaces = ["nsIFile", "nsIPrefLocalizedString"];
+        if (ifaces.includes(valueType.name)) {
+          return this._prefBranch.getComplexValue(prefName, valueType).data;
+        }
+      }
+      return this._prefBranch.getStringPref(prefName);
 
     case Ci.nsIPrefBranch.PREF_INT:
       return this._prefBranch.getIntPref(prefName);
 
     case Ci.nsIPrefBranch.PREF_BOOL:
       return this._prefBranch.getBoolPref(prefName);
 
     case Ci.nsIPrefBranch.PREF_INVALID:
--- a/toolkit/modules/Troubleshoot.jsm
+++ b/toolkit/modules/Troubleshoot.jsm
@@ -99,17 +99,16 @@ const PREFS_WHITELIST = [
 // The blacklist, unlike the whitelist, is a list of regular expressions.
 const PREFS_BLACKLIST = [
   /^network[.]proxy[.]/,
   /[.]print_to_filename$/,
   /^print[.]macosx[.]pagesetup/,
 ];
 
 // Table of getters for various preference types.
-// It's important to use getComplexValue for strings: it returns Unicode (wchars), getCharPref returns UTF-8 encoded chars.
 const PREFS_GETTERS = {};
 
 PREFS_GETTERS[Ci.nsIPrefBranch.PREF_STRING] = (prefs, name) => prefs.getStringPref(name);
 PREFS_GETTERS[Ci.nsIPrefBranch.PREF_INT] = (prefs, name) => prefs.getIntPref(name);
 PREFS_GETTERS[Ci.nsIPrefBranch.PREF_BOOL] = (prefs, name) => prefs.getBoolPref(name);
 
 // Return the preferences filtered by PREFS_BLACKLIST and PREFS_WHITELIST lists
 // and also by the custom 'filter'-ing function.
--- a/toolkit/modules/tests/xpcshell/test_Preferences.js
+++ b/toolkit/modules/tests/xpcshell/test_Preferences.js
@@ -107,19 +107,17 @@ add_test(function test_set_unsupported_p
     Preferences.set("test_set_unsupported_pref", []);
     // We expect this to throw, so the test is designed to fail if it doesn't.
     do_check_true(false);
   } catch (ex) {}
 
   run_next_test();
 });
 
-// Make sure that we can get a string pref that we didn't set ourselves
-// (i.e. that the way we get a string pref using getComplexValue doesn't
-// hork us getting a string pref that wasn't set using setComplexValue).
+// Make sure that we can get a string pref that we didn't set ourselves.
 add_test(function test_get_string_pref() {
   let svc = Cc["@mozilla.org/preferences-service;1"].
             getService(Ci.nsIPrefService).
             getBranch("");
   svc.setCharPref("test_get_string_pref", "a normal string");
   do_check_eq(Preferences.get("test_get_string_pref"), "a normal string");
 
   // Clean up.
--- a/tools/lint/docs/linters/eslint-plugin-mozilla.rst
+++ b/tools/lint/docs/linters/eslint-plugin-mozilla.rst
@@ -54,21 +54,16 @@ Often timing relative to the page load i
 be necessary.
 
 avoid-removeChild
 -----------------
 
 Rejects using element.parentNode.removeChild(element) when element.remove()
 can be used instead.
 
-avoid-nsISupportsString-preferences
------------------------------------
-
-Rejects using getComplexValue and setComplexValue with nsISupportsString.
-
 balanced-listeners
 ------------------
 
 Checks that for every occurence of 'addEventListener' or 'on' there is an
 occurence of 'removeEventListener' or 'off' with the same event name.
 
 import-browser-window-globals
 -----------------------------
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js
@@ -132,17 +132,16 @@ module.exports = {
 
     // Don't enforce the maximum depth that blocks can be nested. The complexity
     // rule is a better rule to check this.
     "max-depth": "off",
 
     // Maximum depth callbacks can be nested.
     "max-nested-callbacks": ["error", 10],
 
-    "mozilla/avoid-nsISupportsString-preferences": "error",
     "mozilla/avoid-removeChild": "error",
     "mozilla/import-browser-window-globals": "error",
     "mozilla/import-globals": "error",
     "mozilla/no-import-into-var-and-global": "error",
     "mozilla/no-useless-parameters": "error",
     "mozilla/no-useless-removeEventListener": "error",
     "mozilla/use-default-preference-values": "error",
     "mozilla/use-ownerGlobal": "error",
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
@@ -27,18 +27,16 @@ module.exports = {
     "simpletest": require("../lib/environments/simpletest.js")
   },
   processors: {
     ".xml": require("../lib/processors/xbl-bindings")
   },
   rules: {
     "avoid-Date-timing": require("../lib/rules/avoid-Date-timing"),
     "avoid-removeChild": require("../lib/rules/avoid-removeChild"),
-    "avoid-nsISupportsString-preferences":
-      require("../lib/rules/avoid-nsISupportsString-preferences"),
     "balanced-listeners": require("../lib/rules/balanced-listeners"),
     "import-browser-window-globals":
       require("../lib/rules/import-browser-window-globals"),
     "import-content-task-globals":
       require("../lib/rules/import-content-task-globals"),
     "import-globals": require("../lib/rules/import-globals"),
     "import-headjs-globals": require("../lib/rules/import-headjs-globals"),
     "mark-test-function-used": require("../lib/rules/mark-test-function-used"),
@@ -61,17 +59,16 @@ module.exports = {
       require("../lib/rules/use-default-preference-values"),
     "use-ownerGlobal": require("../lib/rules/use-ownerGlobal"),
     "use-services": require("../lib/rules/use-services"),
     "var-only-at-top-level": require("../lib/rules/var-only-at-top-level")
   },
   rulesConfig: {
     "avoid-Date-timing": "off",
     "avoid-removeChild": "off",
-    "avoid-nsISupportsString-preferences": "off",
     "balanced-listeners": "off",
     "import-browser-window-globals": "off",
     "import-content-task-globals": "off",
     "import-globals": "off",
     "import-headjs-globals": "off",
     "mark-test-function-used": "off",
     "no-aArgs": "off",
     "no-arbitrary-setTimeout": "off",
deleted file mode 100644
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/avoid-nsISupportsString-preferences.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * @fileoverview Rejects using getComplexValue and setComplexValue with
- *               nsISupportsString.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-"use strict";
-
-// -----------------------------------------------------------------------------
-// Rule Definition
-// -----------------------------------------------------------------------------
-
-function isNsISupportsString(arg) {
-  let isNsISupportsStringIdentifier = obj =>
-    obj.type == "Identifier" && obj.name == "nsISupportsString";
-  return isNsISupportsStringIdentifier(arg) ||
-         (arg.type == "MemberExpression" &&
-          isNsISupportsStringIdentifier(arg.property));
-}
-
-module.exports = function(context) {
-
-  // ---------------------------------------------------------------------------
-  // Public
-  //  --------------------------------------------------------------------------
-
-  return {
-    "CallExpression": function(node) {
-      let callee = node.callee;
-      if (callee.type !== "MemberExpression" ||
-          callee.property.type !== "Identifier" ||
-          node.arguments.length < 2 ||
-          !isNsISupportsString(node.arguments[1])) {
-        return;
-      }
-
-      if (callee.property.name == "getComplexValue") {
-        context.report(node, "use getStringPref instead of " +
-                             "getComplexValue with nsISupportsString");
-      } else if (callee.property.name == "setComplexValue") {
-        context.report(node, "use setStringPref instead of " +
-                             "setComplexValue with nsISupportsString");
-      }
-    }
-  };
-};
--- a/tools/lint/eslint/eslint-plugin-mozilla/package.json
+++ b/tools/lint/eslint/eslint-plugin-mozilla/package.json
@@ -1,11 +1,11 @@
 {
   "name": "eslint-plugin-mozilla",
-  "version": "0.4.6",
+  "version": "0.4.7",
   "description": "A collection of rules that help enforce JavaScript coding standard in the Mozilla project.",
   "keywords": [
     "eslint",
     "eslintplugin",
     "eslint-plugin",
     "mozilla",
     "firefox"
   ],
deleted file mode 100644
--- a/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-nsISupportsString-preferences.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// ------------------------------------------------------------------------------
-// Requirements
-// ------------------------------------------------------------------------------
-
-var rule = require("../lib/rules/avoid-nsISupportsString-preferences");
-var RuleTester = require("eslint/lib/testers/rule-tester");
-
-const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
-
-// ------------------------------------------------------------------------------
-// Tests
-// ------------------------------------------------------------------------------
-
-function invalidCode(code, accessType = "get") {
-  let message = "use " + accessType + "StringPref instead of " +
-                accessType + "ComplexValue with nsISupportsString";
-  return {code, errors: [{message, type: "CallExpression"}]};
-}
-
-ruleTester.run("avoid-nsISupportsString-preferences", rule, {
-  valid: [
-    "branch.getStringPref('name');",
-    "branch.getComplexValue('name', Ci.nsIPrefLocalizedString);",
-    "branch.setStringPref('name', 'blah');",
-    "branch.setComplexValue('name', Ci.nsIPrefLocalizedString, pref);"
-  ],
-  invalid: [
-    invalidCode("branch.getComplexValue('name', Ci.nsISupportsString);"),
-    invalidCode("branch.getComplexValue('name', nsISupportsString);"),
-    invalidCode("branch.getComplexValue('name', Ci.nsISupportsString).data;"),
-    invalidCode("branch.setComplexValue('name', Ci.nsISupportsString, str);",
-                "set"),
-    invalidCode("branch.setComplexValue('name', nsISupportsString, str);",
-                "set")
-  ]
-});