Commit 5de8947f15cecf5f0496ecbe9ec7c68441665a45

Michael Schmidt 2021-09-01T14:04:46

C++: Fixed generic function false positive (#3043)

diff --git a/components/prism-cpp.js b/components/prism-cpp.js
index 033eba6..cffefb0 100644
--- a/components/prism-cpp.js
+++ b/components/prism-cpp.js
@@ -61,7 +61,7 @@
 
 	Prism.languages.insertBefore('cpp', 'keyword', {
 		'generic-function': {
-			pattern: /\b[a-z_]\w*\s*<(?:[^<>]|<(?:[^<>])*>)*>(?=\s*\()/i,
+			pattern: /\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,
 			inside: {
 				'function': /^\w+/,
 				'generic': {
diff --git a/components/prism-cpp.min.js b/components/prism-cpp.min.js
index 03920d5..ee85826 100644
--- a/components/prism-cpp.min.js
+++ b/components/prism-cpp.min.js
@@ -1 +1 @@
-!function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char8_t|char16_t|char32_t|class|compl|concept|const|consteval|constexpr|constinit|const_cast|continue|co_await|co_return|co_yield|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n="\\b(?!<keyword>)\\w+(?:\\s*\\.\\s*\\w+)*\\b".replace(/<keyword>/g,function(){return t.source});e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp("(\\b(?:class|concept|enum|struct|typename)\\s+)(?!<keyword>)\\w+".replace(/<keyword>/g,function(){return t.source})),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:true|false)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp('(\\b(?:module|import)\\s+)(?:"(?:\\\\(?:\r\n|[^])|[^"\\\\\r\n])*"|<[^<>\r\n]*>|'+"<mod-name>(?:\\s*:\\s*<mod-name>)?|:\\s*<mod-name>".replace(/<mod-name>/g,function(){return n})+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b[a-z_]\w*\s*<(?:[^<>]|<(?:[^<>])*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(Prism);
\ No newline at end of file
+!function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char8_t|char16_t|char32_t|class|compl|concept|const|consteval|constexpr|constinit|const_cast|continue|co_await|co_return|co_yield|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n="\\b(?!<keyword>)\\w+(?:\\s*\\.\\s*\\w+)*\\b".replace(/<keyword>/g,function(){return t.source});e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp("(\\b(?:class|concept|enum|struct|typename)\\s+)(?!<keyword>)\\w+".replace(/<keyword>/g,function(){return t.source})),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:true|false)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp('(\\b(?:module|import)\\s+)(?:"(?:\\\\(?:\r\n|[^])|[^"\\\\\r\n])*"|<[^<>\r\n]*>|'+"<mod-name>(?:\\s*:\\s*<mod-name>)?|:\\s*<mod-name>".replace(/<mod-name>/g,function(){return n})+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(Prism);
\ No newline at end of file
diff --git a/tests/languages/cpp/issue3042.test b/tests/languages/cpp/issue3042.test
new file mode 100644
index 0000000..ab5c47b
--- /dev/null
+++ b/tests/languages/cpp/issue3042.test
@@ -0,0 +1,126 @@
+class Foo
+{
+public:
+
+	friend bool operator== (const Foo& f1, const Foo& f2);
+	friend bool operator!= (const Foo& f1, const Foo& f2);
+
+	friend bool operator< (const Foo& f1, const Foo& f2);
+	friend bool operator> (const Foo& f1, const Foo& f2);
+
+	friend bool operator<= (const Foo& f1, const Foo& f2);
+	friend bool operator>= (const Foo& f1, const Foo& f2);
+};
+
+----------------------------------------------------
+
+[
+	["keyword", "class"], ["class-name", "Foo"],
+	["punctuation", "{"],
+	["keyword", "public"], ["operator", ":"],
+
+	["keyword", "friend"],
+	["keyword", "bool"],
+	["keyword", "operator"],
+	["operator", "=="],
+	["punctuation", "("],
+	["keyword", "const"],
+	" Foo",
+	["operator", "&"],
+	" f1",
+	["punctuation", ","],
+	["keyword", "const"],
+	" Foo",
+	["operator", "&"],
+	" f2",
+	["punctuation", ")"],
+	["punctuation", ";"],
+
+	["keyword", "friend"],
+	["keyword", "bool"],
+	["keyword", "operator"],
+	["operator", "!="],
+	["punctuation", "("],
+	["keyword", "const"],
+	" Foo",
+	["operator", "&"],
+	" f1",
+	["punctuation", ","],
+	["keyword", "const"],
+	" Foo",
+	["operator", "&"],
+	" f2",
+	["punctuation", ")"],
+	["punctuation", ";"],
+
+	["keyword", "friend"],
+	["keyword", "bool"],
+	["keyword", "operator"],
+	["operator", "<"],
+	["punctuation", "("],
+	["keyword", "const"],
+	" Foo",
+	["operator", "&"],
+	" f1",
+	["punctuation", ","],
+	["keyword", "const"],
+	" Foo",
+	["operator", "&"],
+	" f2",
+	["punctuation", ")"],
+	["punctuation", ";"],
+
+	["keyword", "friend"],
+	["keyword", "bool"],
+	["keyword", "operator"],
+	["operator", ">"],
+	["punctuation", "("],
+	["keyword", "const"],
+	" Foo",
+	["operator", "&"],
+	" f1",
+	["punctuation", ","],
+	["keyword", "const"],
+	" Foo",
+	["operator", "&"],
+	" f2",
+	["punctuation", ")"],
+	["punctuation", ";"],
+
+	["keyword", "friend"],
+	["keyword", "bool"],
+	["keyword", "operator"],
+	["operator", "<="],
+	["punctuation", "("],
+	["keyword", "const"],
+	" Foo",
+	["operator", "&"],
+	" f1",
+	["punctuation", ","],
+	["keyword", "const"],
+	" Foo",
+	["operator", "&"],
+	" f2",
+	["punctuation", ")"],
+	["punctuation", ";"],
+
+	["keyword", "friend"],
+	["keyword", "bool"],
+	["keyword", "operator"],
+	["operator", ">="],
+	["punctuation", "("],
+	["keyword", "const"],
+	" Foo",
+	["operator", "&"],
+	" f1",
+	["punctuation", ","],
+	["keyword", "const"],
+	" Foo",
+	["operator", "&"],
+	" f2",
+	["punctuation", ")"],
+	["punctuation", ";"],
+
+	["punctuation", "}"],
+	["punctuation", ";"]
+]