|
1 | 1 | use node_types::{EntryKind, Field, NodeTypeMap, Storage, TypeName}; |
| 2 | +use std::borrow::Cow; |
2 | 3 | use std::collections::BTreeMap as Map; |
3 | 4 | use std::collections::BTreeSet as Set; |
4 | 5 | use std::fmt; |
@@ -192,20 +193,37 @@ pub fn extract( |
192 | 193 |
|
193 | 194 | /// Escapes a string for use in a TRAP key, by replacing special characters with |
194 | 195 | /// HTML entities. |
195 | | -fn escape_key(s: &str) -> String { |
196 | | - let mut escaped = String::new(); |
197 | | - for c in s.chars() { |
| 196 | +fn escape_key<'a, S: Into<Cow<'a, str>>>(key: S) -> Cow<'a, str> { |
| 197 | + fn needs_escaping(c: char) -> bool { |
198 | 198 | match c { |
199 | | - '&' => escaped.push_str("&"), |
200 | | - '{' => escaped.push_str("{"), |
201 | | - '}' => escaped.push_str("}"), |
202 | | - '"' => escaped.push_str("""), |
203 | | - '@' => escaped.push_str("@"), |
204 | | - '#' => escaped.push_str("#"), |
205 | | - _ => escaped.push(c), |
| 199 | + '&' => true, |
| 200 | + '{' => true, |
| 201 | + '}' => true, |
| 202 | + '"' => true, |
| 203 | + '@' => true, |
| 204 | + '#' => true, |
| 205 | + _ => false, |
206 | 206 | } |
207 | 207 | } |
208 | | - escaped |
| 208 | + |
| 209 | + let key = key.into(); |
| 210 | + if key.contains(needs_escaping) { |
| 211 | + let mut escaped = String::with_capacity(key.len()); |
| 212 | + for c in key.chars() { |
| 213 | + match c { |
| 214 | + '&' => escaped.push_str("&"), |
| 215 | + '{' => escaped.push_str("{"), |
| 216 | + '}' => escaped.push_str("}"), |
| 217 | + '"' => escaped.push_str("""), |
| 218 | + '@' => escaped.push_str("@"), |
| 219 | + '#' => escaped.push_str("#"), |
| 220 | + _ => escaped.push(c), |
| 221 | + } |
| 222 | + } |
| 223 | + Cow::Owned(escaped) |
| 224 | + } else { |
| 225 | + key |
| 226 | + } |
209 | 227 | } |
210 | 228 |
|
211 | 229 | /// Normalizes the path according the common CodeQL specification. Assumes that |
|
0 commit comments