checker.h (3175B)
1 // Copyright 2020 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ 16 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ 17 18 #include <algorithm> 19 20 #include "absl/base/attributes.h" 21 #include "absl/strings/internal/str_format/arg.h" 22 #include "absl/strings/internal/str_format/constexpr_parser.h" 23 #include "absl/strings/internal/str_format/extension.h" 24 25 // Compile time check support for entry points. 26 27 #ifndef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 28 // We disable format checker under vscode intellisense compilation. 29 // See https://github.com/microsoft/vscode-cpptools/issues/3683 for 30 // more details. 31 #if ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__) && \ 32 !defined(__INTELLISENSE__) 33 #define ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 1 34 #endif // ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__) && 35 // !defined(__INTELLISENSE__) 36 #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 37 38 namespace absl { 39 ABSL_NAMESPACE_BEGIN 40 namespace str_format_internal { 41 42 #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 43 44 template <FormatConversionCharSet... C> 45 constexpr bool ValidFormatImpl(string_view format) { 46 int next_arg = 0; 47 const char* p = format.data(); 48 const char* const end = p + format.size(); 49 constexpr FormatConversionCharSet 50 kAllowedConvs[(std::max)(sizeof...(C), size_t{1})] = {C...}; 51 bool used[(std::max)(sizeof...(C), size_t{1})]{}; 52 constexpr int kNumArgs = sizeof...(C); 53 while (p != end) { 54 while (p != end && *p != '%') ++p; 55 if (p == end) { 56 break; 57 } 58 if (p + 1 >= end) return false; 59 if (p[1] == '%') { 60 // %% 61 p += 2; 62 continue; 63 } 64 65 UnboundConversion conv(absl::kConstInit); 66 p = ConsumeUnboundConversion(p + 1, end, &conv, &next_arg); 67 if (p == nullptr) return false; 68 if (conv.arg_position <= 0 || conv.arg_position > kNumArgs) { 69 return false; 70 } 71 if (!Contains(kAllowedConvs[conv.arg_position - 1], conv.conv)) { 72 return false; 73 } 74 used[conv.arg_position - 1] = true; 75 for (auto extra : {conv.width, conv.precision}) { 76 if (extra.is_from_arg()) { 77 int pos = extra.get_from_arg(); 78 if (pos <= 0 || pos > kNumArgs) return false; 79 used[pos - 1] = true; 80 if (!Contains(kAllowedConvs[pos - 1], '*')) { 81 return false; 82 } 83 } 84 } 85 } 86 if (sizeof...(C) != 0) { 87 for (bool b : used) { 88 if (!b) return false; 89 } 90 } 91 return true; 92 } 93 94 #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 95 96 } // namespace str_format_internal 97 ABSL_NAMESPACE_END 98 } // namespace absl 99 100 #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_