[llvm] [Instrumentor] Add spellcheck for instrumentor properties (PR #205416)

Ethan Luis McDonough via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 24 21:27:21 PDT 2026


https://github.com/EthanLuisMcDonough updated https://github.com/llvm/llvm-project/pull/205416

>From a41df7afe72a6c917386446e4bfd2c7532c018d4 Mon Sep 17 00:00:00 2001
From: Ethan Luis McDonough <ethanluismcdonough at gmail.com>
Date: Tue, 23 Jun 2026 14:31:40 -0500
Subject: [PATCH 1/2] Add spellcheck for instrumentor properties

---
 .../Transforms/IPO/InstrumentorConfigFile.cpp | 57 ++++++++++++++++---
 .../Instrumentor/bad_spelling.ll              |  7 +++
 .../Instrumentor/bad_spelling_config.json     | 30 ++++++++++
 3 files changed, 86 insertions(+), 8 deletions(-)
 create mode 100644 llvm/test/Instrumentation/Instrumentor/bad_spelling.ll
 create mode 100644 llvm/test/Instrumentation/Instrumentor/bad_spelling_config.json

diff --git a/llvm/lib/Transforms/IPO/InstrumentorConfigFile.cpp b/llvm/lib/Transforms/IPO/InstrumentorConfigFile.cpp
index 1038badc189a6..f93febaa56e5e 100644
--- a/llvm/lib/Transforms/IPO/InstrumentorConfigFile.cpp
+++ b/llvm/lib/Transforms/IPO/InstrumentorConfigFile.cpp
@@ -112,6 +112,20 @@ void writeConfigToJSON(InstrumentationConfig &IConf, StringRef OutputFile,
   J.objectEnd();
 }
 
+template <typename Map>
+static StringRef closestOption(const Map &Options, StringRef Missing) {
+  uint32_t MaxEdit = 5;
+  StringRef Closest;
+  for (auto Key : Options.keys()) {
+    auto EditDist = Missing.edit_distance_insensitive(Key, true, MaxEdit);
+    if (EditDist < MaxEdit) {
+      Closest = Key;
+      MaxEdit = EditDist;
+    }
+  }
+  return Closest;
+}
+
 bool readConfigFromJSON(InstrumentationConfig &IConf, StringRef InputFile,
                         LLVMContext &Ctx, vfs::FileSystem &FS) {
   if (InputFile.empty())
@@ -182,10 +196,15 @@ bool readConfigFromJSON(InstrumentationConfig &IConf, StringRef InputFile,
             break;
           }
         } else if (!StringRef(ObjIt.first).ends_with(".description")) {
-          Ctx.diagnose(DiagnosticInfoInstrumentation(
-              Twine("configuration key '") + StringRef(ObjIt.first) +
-                  Twine("' not found and ignored"),
-              DS_Warning));
+          Twine NoMatchingMsg = Twine("configuration key '") +
+                                StringRef(ObjIt.first) +
+                                Twine("' not found and ignored");
+          StringRef Closest = closestOption(BCOMap, ObjIt.first);
+          Twine Diag =
+              NoMatchingMsg + (Closest.empty() ? Twine()
+                                               : Twine("; did you mean '") +
+                                                     Closest + Twine("'?"));
+          Ctx.diagnose(DiagnosticInfoInstrumentation(Diag, DS_Warning));
         }
       }
       continue;
@@ -202,16 +221,27 @@ bool readConfigFromJSON(InstrumentationConfig &IConf, StringRef InputFile,
       }
       auto *IO = IChoiceMap.lookup(ObjIt.first);
       if (!IO) {
-        Ctx.diagnose(DiagnosticInfoInstrumentation(
+        Twine NoMatchingMsg =
             Twine("malformed JSON configuration, expected an object matching "
-                  "an instrumentor choice, got ") +
-                StringRef(ObjIt.first),
-            DS_Warning));
+                  "an instrumentor choice, got '") +
+            StringRef(ObjIt.first) + Twine("'");
+        StringRef Closest = closestOption(IChoiceMap, ObjIt.first);
+        Twine Diag = NoMatchingMsg +
+                     (Closest.empty()
+                          ? Twine()
+                          : Twine("; did you mean '") + Closest + Twine("'?"));
+        Ctx.diagnose(DiagnosticInfoInstrumentation(Diag, DS_Warning));
         continue;
       }
       SeenIOs.insert(IO);
       StringMap<bool> ValueMap, ReplaceMap;
       StringRef FilterStr;
+      StringSet<> IOOpts;
+      IOOpts.insert("enabled");
+      IOOpts.insert("filter");
+      for (auto &IRArg : IO->IRTArgs) {
+        IOOpts.insert(IRArg.Name);
+      }
       for (auto &InnerObjIt : *InnerObj) {
         auto Name = StringRef(InnerObjIt.first);
         if (Name == "filter") {
@@ -222,6 +252,17 @@ bool readConfigFromJSON(InstrumentationConfig &IConf, StringRef InputFile,
         } else {
           ValueMap[Name] = InnerObjIt.second.getAsBoolean().value_or(false);
         }
+        if (!IOOpts.contains(Name)) {
+          Twine NoMatchingMsg = Twine("unrecognized JSON property '") +
+                                StringRef(Name) + ("' in configuration for '") +
+                                IO->getName() + Twine("'");
+          StringRef Closest = closestOption(IOOpts, Name);
+          Twine Diag =
+              NoMatchingMsg + (Closest.empty() ? Twine()
+                                               : Twine("; did you mean '") +
+                                                     Closest + Twine("'?"));
+          Ctx.diagnose(DiagnosticInfoInstrumentation(Diag, DS_Warning));
+        }
       }
       IO->Enabled = ValueMap["enabled"];
       IO->Filter = FilterStr;
diff --git a/llvm/test/Instrumentation/Instrumentor/bad_spelling.ll b/llvm/test/Instrumentation/Instrumentor/bad_spelling.ll
new file mode 100644
index 0000000000000..92f2701a18522
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/bad_spelling.ll
@@ -0,0 +1,7 @@
+; RUN: opt < %s -passes=instrumentor -instrumentor-read-config-files=%S/bad_spelling_config.json -S 2>&1 | FileCheck %s
+
+; CHECK: warning: configuration key 'gpu_enabeld' not found and ignored; did you mean 'gpu_enabled'?
+; CHECK: warning: malformed JSON configuration, expected an object matching an instrumentor choice, got 'numerci'; did you mean 'numeric'?
+; CHECK: warning: unrecognized JSON property 'zzzzzz' in configuration for 'numeric'
+; CHECK: warning: unrecognized JSON property 'opocde' in configuration for 'numeric'; did you mean 'opcode'?
+; CHECK: warning: unrecognized JSON property 'enabld' in configuration for 'numeric'; did you mean 'enabled'?
diff --git a/llvm/test/Instrumentation/Instrumentor/bad_spelling_config.json b/llvm/test/Instrumentation/Instrumentor/bad_spelling_config.json
new file mode 100644
index 0000000000000..f0fa47ca0b4a5
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/bad_spelling_config.json
@@ -0,0 +1,30 @@
+{
+  "configuration": {
+    "runtime_prefix": "__instrumentor_",
+    "gpu_enabeld": false
+  },
+  "instruction_pre": {
+    "numeric": {
+      "enabld": true,
+      "type_id": true,
+      "size": true,
+      "opocde": true,
+      "left": true,
+      "right": true,
+      "zzzzzz": false,
+      "id": true
+    }
+  },
+  "instruction_post": {
+    "numerci": {
+      "enabled": true,
+      "type_id": true,
+      "size": true,
+      "opcode": true,
+      "left": true,
+      "right": true,
+      "result": true,
+      "id": true
+    }
+  }
+}

>From f71308eb227c4137eddc1b51cda4daaa0c1dfc35 Mon Sep 17 00:00:00 2001
From: Ethan Luis McDonough <ethanluismcdonough at gmail.com>
Date: Wed, 24 Jun 2026 20:25:57 -0500
Subject: [PATCH 2/2] Minor adjustments

---
 llvm/lib/Transforms/IPO/InstrumentorConfigFile.cpp     | 6 +++---
 llvm/test/Instrumentation/Instrumentor/bad_spelling.ll | 8 ++++----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/InstrumentorConfigFile.cpp b/llvm/lib/Transforms/IPO/InstrumentorConfigFile.cpp
index f93febaa56e5e..f045509cc798e 100644
--- a/llvm/lib/Transforms/IPO/InstrumentorConfigFile.cpp
+++ b/llvm/lib/Transforms/IPO/InstrumentorConfigFile.cpp
@@ -15,6 +15,7 @@
 
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -116,7 +117,7 @@ template <typename Map>
 static StringRef closestOption(const Map &Options, StringRef Missing) {
   uint32_t MaxEdit = 5;
   StringRef Closest;
-  for (auto Key : Options.keys()) {
+  for (const auto &Key : Options.keys()) {
     auto EditDist = Missing.edit_distance_insensitive(Key, true, MaxEdit);
     if (EditDist < MaxEdit) {
       Closest = Key;
@@ -239,9 +240,8 @@ bool readConfigFromJSON(InstrumentationConfig &IConf, StringRef InputFile,
       StringSet<> IOOpts;
       IOOpts.insert("enabled");
       IOOpts.insert("filter");
-      for (auto &IRArg : IO->IRTArgs) {
+      for (auto &IRArg : IO->IRTArgs)
         IOOpts.insert(IRArg.Name);
-      }
       for (auto &InnerObjIt : *InnerObj) {
         auto Name = StringRef(InnerObjIt.first);
         if (Name == "filter") {
diff --git a/llvm/test/Instrumentation/Instrumentor/bad_spelling.ll b/llvm/test/Instrumentation/Instrumentor/bad_spelling.ll
index 92f2701a18522..4b1808b78624f 100644
--- a/llvm/test/Instrumentation/Instrumentor/bad_spelling.ll
+++ b/llvm/test/Instrumentation/Instrumentor/bad_spelling.ll
@@ -1,7 +1,7 @@
 ; RUN: opt < %s -passes=instrumentor -instrumentor-read-config-files=%S/bad_spelling_config.json -S 2>&1 | FileCheck %s
 
-; CHECK: warning: configuration key 'gpu_enabeld' not found and ignored; did you mean 'gpu_enabled'?
 ; CHECK: warning: malformed JSON configuration, expected an object matching an instrumentor choice, got 'numerci'; did you mean 'numeric'?
-; CHECK: warning: unrecognized JSON property 'zzzzzz' in configuration for 'numeric'
-; CHECK: warning: unrecognized JSON property 'opocde' in configuration for 'numeric'; did you mean 'opcode'?
-; CHECK: warning: unrecognized JSON property 'enabld' in configuration for 'numeric'; did you mean 'enabled'?
+; CHECK-NEXT: warning: configuration key 'gpu_enabeld' not found and ignored; did you mean 'gpu_enabled'?
+; CHECK-NEXT: warning: unrecognized JSON property 'opocde' in configuration for 'numeric'; did you mean 'opcode'?
+; CHECK-NEXT: warning: unrecognized JSON property 'zzzzzz' in configuration for 'numeric'
+; CHECK-NEXT: warning: unrecognized JSON property 'enabld' in configuration for 'numeric'; did you mean 'enabled'?
\ No newline at end of file



More information about the llvm-commits mailing list