Summary: Reimplement whitelists as a match against a single regexp. This allows one to precompile the whitelist regexp to make fast check against a whitelist of fuzzy qualifiers, instead of checks linear in the number of items in the whitelist. Reviewed By: akotulski Differential Revision: D4588278 fbshipit-source-id: 3bac614master
parent
7e1f1f9101
commit
f1698f3816
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
open! IStd;
|
||||||
|
|
||||||
|
type quals_matcher = Str.regexp;
|
||||||
|
|
||||||
|
let regexp_string_of_qualifiers quals => {
|
||||||
|
let is_std_qual = String.equal "std";
|
||||||
|
let qualifiers_simple_matcher quals => Str.quote (String.concat sep::"::" quals) ^ "$";
|
||||||
|
switch quals {
|
||||||
|
| [first, ...[_, ..._] as rest] when is_std_qual first =>
|
||||||
|
/* add special handling for std:: namespace to avoid problems with inconsistent
|
||||||
|
inline namespaces (such as __1 in libc++) */
|
||||||
|
Str.quote first ^ "\\(::[^:]*\\)?::" ^ qualifiers_simple_matcher rest
|
||||||
|
| _ => qualifiers_simple_matcher quals
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let qualifiers_list_matcher quals_list =>
|
||||||
|
(
|
||||||
|
if (List.is_empty quals_list) {
|
||||||
|
"a^" /* regexp that does not match anything */
|
||||||
|
} else {
|
||||||
|
List.map f::regexp_string_of_qualifiers quals_list |> String.concat sep::"\\|"
|
||||||
|
}
|
||||||
|
) |> Str.regexp;
|
||||||
|
|
||||||
|
let match_qualifiers matcher quals => {
|
||||||
|
let normalized_qualifiers = {
|
||||||
|
/* qual_name may have qualifiers with template parameters - drop them to whitelist all
|
||||||
|
instantiations */
|
||||||
|
let no_template_name s => List.hd_exn (String.split on::'<' s);
|
||||||
|
List.map f::no_template_name quals
|
||||||
|
};
|
||||||
|
Str.string_match matcher (String.concat sep::"::" normalized_qualifiers) 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This is simplistic and will give the wrong answer in some cases, eg
|
||||||
|
"foo<bar::baz<goo>>::someMethod" will get parsed as ["foo<bar", "baz<goo>>",
|
||||||
|
"someMethod"]. Ideally, we would keep the list of qualifiers in the procname, which would save us
|
||||||
|
from having to properly parse them. */
|
||||||
|
let qualifiers_of_qual_name = {
|
||||||
|
let class_sep_regex = Str.regexp_string "::";
|
||||||
|
/* wait until here to define the function so that [class_sep_regex] is only computed once */
|
||||||
|
Str.split class_sep_regex
|
||||||
|
};
|
||||||
|
|
||||||
|
let qualifiers_of_fuzzy_qual_name qual_name => {
|
||||||
|
/* Fail if we detect templates in the fuzzy name. Template instantiations are not taken into
|
||||||
|
account when fuzzy matching, and templates may produce wrong results when parsing qualified
|
||||||
|
names. */
|
||||||
|
if (String.contains qual_name '<') {
|
||||||
|
failwithf "Unexpected template in fuzzy qualified name %s." qual_name
|
||||||
|
};
|
||||||
|
qualifiers_of_qual_name qual_name
|
||||||
|
};
|
||||||
|
|
||||||
|
let quals_matcher_of_fuzzy_qual_names fuzzy_qual_names =>
|
||||||
|
List.map fuzzy_qual_names f::qualifiers_of_fuzzy_qual_name |> qualifiers_list_matcher;
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
open! IStd;
|
||||||
|
|
||||||
|
/* Module to match qualified C++ procnames "fuzzily", that is up to namescapes and templating. In
|
||||||
|
particular, this deals with the following issues:
|
||||||
|
|
||||||
|
1. 'std::' namespace may have inline namespace afterwards: std::move becomes std::__1::move. This
|
||||||
|
happens on libc++ and to some extent on libstdc++. To work around this problem, make matching
|
||||||
|
against 'std::' more fuzzier: std::X::Y::Z will match std::.*::X::Y::Z (but only for the
|
||||||
|
'std' namespace).
|
||||||
|
|
||||||
|
2. The names are allowed not to commit to a template specialization: we want std::move to match
|
||||||
|
std::__1::move<const X&> and std::__1::move<int>. To do so, comparison function for qualifiers
|
||||||
|
will ignore template specializations.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
["std", "move"]:
|
||||||
|
matches: ["std", "blah", "move"]
|
||||||
|
matches: ["std", "blah<int>", "move"]
|
||||||
|
does not match: ["std","blah", "move", "BAD"] - we don't want std::.*::X::.* to pass
|
||||||
|
does not match: ["stdBAD", "move"], - it's not std namespace anymore
|
||||||
|
|
||||||
|
["folly", "someFunction"]
|
||||||
|
matches: ["folly","someFunction"]
|
||||||
|
matches: ["folly","someFunction<int>"]
|
||||||
|
matches: ["folly<int>","someFunction"]
|
||||||
|
does not match: ["folly", "BAD", "someFunction"] - unlike 'std' any other namespace needs all
|
||||||
|
qualifiers to match
|
||||||
|
does not match: ["folly","someFunction<int>", "BAD"] - same as previous example
|
||||||
|
*/
|
||||||
|
type quals_matcher;
|
||||||
|
|
||||||
|
let quals_matcher_of_fuzzy_qual_names: list string => quals_matcher;
|
||||||
|
|
||||||
|
let match_qualifiers: quals_matcher => list string => bool;
|
||||||
|
|
||||||
|
|
||||||
|
/** attempts to parse the argument into a list::of::possibly::templated<T>::qualifiers */
|
||||||
|
let qualifiers_of_qual_name: string => list string;
|
@ -0,0 +1,133 @@
|
|||||||
|
(*
|
||||||
|
* Copyright (c) 2017 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*)
|
||||||
|
|
||||||
|
open! IStd
|
||||||
|
open OUnit2
|
||||||
|
|
||||||
|
let test_fuzzy_match =
|
||||||
|
let create_test fuzzy_qual_names qualifiers expected_match _ =
|
||||||
|
let output =
|
||||||
|
let matcher = QualifiedCppName.quals_matcher_of_fuzzy_qual_names fuzzy_qual_names in
|
||||||
|
QualifiedCppName.match_qualifiers matcher qualifiers in
|
||||||
|
assert_equal ~cmp:Bool.equal expected_match output in
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"test_simple_match1",
|
||||||
|
["foo::bar::baz"; "foo::baz"; "goo::goo"],
|
||||||
|
["foo"; "baz"],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_simple_match2",
|
||||||
|
["foo::bar::baz"; "foo::baz"; "goo::goo"],
|
||||||
|
["foo"; "bar"; "baz"],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_simple_match3",
|
||||||
|
["foo::bar::baz"; "foo::baz"; "goo::goo"],
|
||||||
|
["goo"; "goo"],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_no_simple_match1",
|
||||||
|
["foo::bar::baz"; "foo::baz"; "goo::goo"],
|
||||||
|
["foo"; "bar"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_no_simple_match2",
|
||||||
|
["foo::bar::baz"; "foo::baz"; "goo::goo"],
|
||||||
|
["goo"; "foo"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_no_simple_match3",
|
||||||
|
["foo::bar::baz"; "foo::baz"; "goo::goo"],
|
||||||
|
["moo"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_no_simple_match4",
|
||||||
|
["foo::bar::baz"; "foo::baz"; "goo::goo"],
|
||||||
|
["foo"; "bar"; "baz"; "bad"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_no_simple_match5",
|
||||||
|
["foo::bar::baz"; "foo::baz"; "goo::goo"],
|
||||||
|
["foo"; "bad"; "bar"; "baz"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_template_match",
|
||||||
|
["foo::bar::baz"],
|
||||||
|
["foo"; "bar<goo::moo<int,std::string>,const X&>"; "baz<int>"],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_std_direct_match",
|
||||||
|
["std::foo"],
|
||||||
|
["std"; "foo"],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_std_direct_no_match1",
|
||||||
|
["std::foo"],
|
||||||
|
["std"; "goo"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_std_direct_no_match2",
|
||||||
|
["std::foo"],
|
||||||
|
["std"; "foo"; "bad"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_std_direct_no_match3",
|
||||||
|
["std::foo"],
|
||||||
|
["stdBAD"; "foo"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_std_fuzzy_match1",
|
||||||
|
["std::foo"],
|
||||||
|
["std"; "__1"; "foo"],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_std_fuzzy_match2",
|
||||||
|
["std::foo"],
|
||||||
|
["std"; "goo<int>"; "foo"],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_std_fuzzy_match3",
|
||||||
|
["std::foo"],
|
||||||
|
["std"; "goo<int>"; "foo<const X&>"],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_std_fuzzy_no_match1",
|
||||||
|
["std::foo"],
|
||||||
|
["std"; "__1"; "__2"; "foo"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
(
|
||||||
|
"test_std_fuzzy_no_match2",
|
||||||
|
["std::foo"],
|
||||||
|
["std"; "__1"; "foo"; "bad"],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
]
|
||||||
|
|> List.map
|
||||||
|
~f:(fun (name, fuzzy_qual_names, qualifiers, expected_output) ->
|
||||||
|
name >:: create_test fuzzy_qual_names qualifiers expected_output)
|
||||||
|
|
||||||
|
let tests = "qualified_cpp_name_fuzzy_match" >::: test_fuzzy_match
|
@ -0,0 +1,11 @@
|
|||||||
|
(*
|
||||||
|
* Copyright (c) 2017 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*)
|
||||||
|
open! IStd
|
||||||
|
|
||||||
|
val tests: OUnit2.test
|
Loading…
Reference in new issue