Repository: clap-rs/clap (Rust)

Issue:
get_arg_conflicts_with panics if arg conflicts with group.
### Please complete the following tasks

- [X] I have searched the [discussions](https://github.com/clap-rs/clap/discussions)
- [X] I have searched the [open](https://github.com/clap-rs/clap/issues) and [rejected](https://github.com/clap-rs/clap/issues?q=is%3Aissue+label%3AS-wont-fix+is%3Aclosed) issues

### Rust Version

rustc 1.62.0 (a8314ef7d 2022-06-27)

### Clap Version

3.2.6

### Minimal reproducible code

```rust
use clap::*;

fn main() {
    let c = Arg::new("c").short('c').conflicts_with("gr");
    let app = Command::new("test")
        .group(ArgGroup::new("gr").args(&["a", "b"]))
        .arg(Arg::new("a").short('a'))
        .arg(Arg::new("b").short('b'))
        .arg(&c);
        
    let res =app.clone().try_get_matches_from(vec!["cmd", "-c", "-a"]);
    if let Err(e) = res {
        assert_eq!(e.kind(), clap::error::ErrorKind::ArgumentConflict);
        e.print().unwrap();
    } else {
        unreachable!();
    }

    println!("conflicts: {:?}", app.get_arg_conflicts_with(&c));
}
```

(see https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6db4239226ac59fd07ccc37d0ce13bdd)


### Steps to reproduce the bug with the above code

Run the code in the minimal reproducible code section above

### Actual Behaviour

Panic with `Command::get_arg_conflicts_with: The passed arg conflicts with an arg unknown to the cmd."

### Expected Behaviour

Return  a vec containing the commands in the "gr" group.

### Additional Context

I encountered this while trying to generate zsh completions for a command that has an arg that conflicts with a group, because clap_complete calls `get_arg_conflicts_with` for each argument when generating zsh completions. 

The correct logic for this must exist somewhere, because as can be seen in the code above, it correctly identifies the conflict when parsing a command containing a conflict with the group.

### Debug Output

_No response_


Discussion:
Also worth pointing out that the documentation states that `get_arg_conflicts_with` gets a "list of all arguments the given argument conflicts with". but from what I can tell, this isn't actually true. It just gets a list of the arguments that are listed as `conflicts_with` for this specific `Arg` value, not other arguments that are specified to conflict with this value.
If I move the `conflicts_with` from the `Arg` to the `ArgGroup`, then it no longer panics, but the zsh shell completion doesn't detect the conflict between the group and the other option. But maybe that should be a separate bug with clap_complete?
> If I move the conflicts_with from the Arg to the ArgGroup, then it no longer panics, but the zsh shell completion doesn't detect the conflict between the group and the other option. But maybe that should be a separate bug with clap_complete?

Yes, that is a separate bug.
v3.2.12 is now released with this

Thanks!



Patch:
diff --git a/src/builder/command.rs b/src/builder/command.rs
index d644cb7681f..7373c6eb0eb 100644
--- a/src/builder/command.rs
+++ b/src/builder/command.rs
@@ -3556,15 +3556,21 @@ impl<'help> App<'help> {
         if arg.is_global_set() {
             self.get_global_arg_conflicts_with(arg)
         } else {
-            arg.blacklist
-                .iter()
-                .map(|id| {
-                    self.args.args().find(|arg| arg.id == *id).expect(
-                        "Command::get_arg_conflicts_with: \
-                    The passed arg conflicts with an arg unknown to the cmd",
-                    )
-                })
-                .collect()
+            let mut result = Vec::new();
+            for id in arg.blacklist.iter() {
+                if let Some(arg) = self.find(id) {
+                    result.push(arg);
+                } else if let Some(group) = self.find_group(id) {
+                    result.extend(
+                        self.unroll_args_in_group(&group.id)
+                            .iter()
+                            .map(|id| self.find(id).expect(INTERNAL_ERROR_MSG)),
+                    );
+                } else {
+                    panic!("Command::get_arg_conflicts_with: The passed arg conflicts with an arg unknown to the cmd");
+                }
+            }
+            result
         }
     }
 


Test patch:
diff --git a/tests/builder/conflicts.rs b/tests/builder/conflicts.rs
index 3c0ef817b9e..cb5e7da7aec 100644
--- a/tests/builder/conflicts.rs
+++ b/tests/builder/conflicts.rs
@@ -296,6 +296,24 @@ fn required_group_conflicts_with_arg() {
     }
 }
 
+#[test]
+fn get_arg_conflicts_with_group() {
+    let flag = arg!(--flag).conflicts_with("gr");
+    let mut cmd = Command::new("group_conflict")
+        .arg(&flag)
+        .group(ArgGroup::new("gr").arg("some").arg("other"))
+        .arg(arg!(--some))
+        .arg(arg!(--other));
+
+    cmd.build();
+
+    let result = cmd.get_arg_conflicts_with(&flag);
+
+    assert_eq!(result.len(), 2);
+    assert_eq!(result[0].get_id(), "some");
+    assert_eq!(result[1].get_id(), "other");
+}
+
 #[test]
 fn conflict_output() {
     utils::assert_output(