mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
Note, not trying to address every last error, just some obvious/easy ones.
```
/usr/local/google/home/jperkins/dev/carbon-lang/common/string_helpers.cpp:200:13: warning: prefer transparent functors 'less_equal<>' [modernize-use-transparent-functors]
auto le = std::less_equal<const char*>();
^
/usr/local/google/home/jperkins/dev/carbon-lang/toolchain/semantics/nodes/function.h:22:45: warning: pass by value and use std::move [modernize-pass-by-value]
Function(ParseTree::Node node, NodeId id, llvm::SmallVector<NodeRef> body)
^
/usr/local/google/home/jperkins/dev/carbon-lang/explorer/ast/declaration.cpp:230:14: warning: static member accessed through instance [readability-static-accessed-through-instance]
return cast<SelfDeclaration>(declaration).name();
^
/usr/local/google/home/jperkins/dev/carbon-lang/explorer/interpreter/type_checker.cpp:1104:33: warning: std::move of the variable 'impl' of the trivially-copyable type 'ConstraintType::ImplConstraint' has no effect [performance-move-const-arg]
impl_constraints_.push_back(std::move(impl));
^
/usr/local/google/home/jperkins/dev/carbon-lang/explorer/interpreter/type_checker.cpp:1145:36: warning: std::move of the variable 'rewrite' of the trivially-copyable type 'ConstraintType::RewriteConstraint' has no effect [performance-move-const-arg]
rewrite_constraints_.push_back(std::move(rewrite));
^
/usr/local/google/home/jperkins/dev/carbon-lang/explorer/interpreter/type_checker.cpp:1156:32: warning: std::move of the variable 'context' of the trivially-copyable type 'ConstraintType::LookupContext' has no effect [performance-move-const-arg]
lookup_contexts_.push_back(std::move(context));
^
/usr/local/google/home/jperkins/dev/carbon-lang/explorer/fuzzing/fuzzverter.cpp:74:42: warning: argument name 'trace' in comment does not match parameter name 'parser_debug' [bugprone-argument-comment]
/*trace=*/false);
^
./explorer/syntax/parse.h:19:17: note: 'parser_debug' declared here
bool parser_debug) -> ErrorOr<Carbon::AST>;
^
/usr/local/google/home/jperkins/dev/carbon-lang/explorer/fuzzing/proto_to_carbon_test.cpp:34:55: warning: argument name 'trace' in comment does not match parameter name 'parser_debug' [bugprone-argument-comment]
const ErrorOr<AST> ast = Carbon::Parse(&arena, f, /*trace=*/false);
^
./explorer/syntax/parse.h:19:17: note: 'parser_debug' declared here
bool parser_debug) -> ErrorOr<Carbon::AST>;
^
/usr/local/google/home/jperkins/dev/carbon-lang/explorer/fuzzing/proto_to_carbon_test.cpp:42:41: warning: argument name 'trace' in comment does not match parameter name 'parser_debug' [bugprone-argument-comment]
&arena, f, source_from_proto, /*trace=*/false);
^
./explorer/syntax/parse.h:25:59: note: 'parser_debug' declared here
std::string_view file_contents, bool parser_debug)
^
/usr/local/google/home/jperkins/dev/carbon-lang/explorer/syntax/parse_test.cpp:27:60: warning: argument name 'trace' in comment does not match parameter name 'parser_debug' [bugprone-argument-comment]
ParseFromString(&arena, "file.carbon", FileContents, /*trace=*/false);
^
./explorer/syntax/parse.h:25:59: note: 'parser_debug' declared here
std::string_view file_contents, bool parser_debug)
^
/usr/local/google/home/jperkins/dev/carbon-lang/migrate_cpp/cpp_refactoring/var_decl.cpp:57:58: warning: string concatenation results in allocation of unnecessary temporary strings; consider using 'operator+=' or 'string::append()' instead [performance-inefficient-string-concatenation]
segments.push_back({type_loc_class, qual_str + " " + range_str});
^
/usr/local/google/home/jperkins/dev/carbon-lang/explorer/fuzzing/ast_to_proto_test.cpp:105:55: warning: argument name 'trace' in comment does not match parameter name 'parser_debug' [bugprone-argument-comment]
const ErrorOr<AST> ast = Carbon::Parse(&arena, f, /*trace=*/false);
^
./explorer/syntax/parse.h:19:17: note: 'parser_debug' declared here
bool parser_debug) -> ErrorOr<Carbon::AST>;
^
```
205 lines
6.1 KiB
C++
205 lines
6.1 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#include "common/string_helpers.h"
|
|
|
|
#include <algorithm>
|
|
#include <optional>
|
|
|
|
#include "common/check.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/ConvertUTF.h"
|
|
|
|
namespace Carbon {
|
|
|
|
static constexpr llvm::StringRef TripleQuotes = R"(""")";
|
|
static constexpr llvm::StringRef HorizontalWhitespaceChars = " \t";
|
|
|
|
// Carbon only takes uppercase hex input.
|
|
static auto FromHex(char c) -> std::optional<char> {
|
|
if (c >= '0' && c <= '9') {
|
|
return c - '0';
|
|
}
|
|
if (c >= 'A' && c <= 'F') {
|
|
return 10 + c - 'A';
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
auto UnescapeStringLiteral(llvm::StringRef source, const int hashtag_num,
|
|
bool is_block_string) -> std::optional<std::string> {
|
|
std::string ret;
|
|
ret.reserve(source.size());
|
|
std::string escape = "\\";
|
|
escape.resize(hashtag_num + 1, '#');
|
|
size_t i = 0;
|
|
while (i < source.size()) {
|
|
char c = source[i];
|
|
if (i + hashtag_num < source.size() &&
|
|
source.slice(i, i + hashtag_num + 1).equals(escape)) {
|
|
i += hashtag_num + 1;
|
|
if (i == source.size()) {
|
|
return std::nullopt;
|
|
}
|
|
switch (source[i]) {
|
|
case 'n':
|
|
ret.push_back('\n');
|
|
break;
|
|
case 'r':
|
|
ret.push_back('\r');
|
|
break;
|
|
case 't':
|
|
ret.push_back('\t');
|
|
break;
|
|
case '0':
|
|
if (i + 1 < source.size() && llvm::isDigit(source[i + 1])) {
|
|
// \0[0-9] is reserved.
|
|
return std::nullopt;
|
|
}
|
|
ret.push_back('\0');
|
|
break;
|
|
case '"':
|
|
ret.push_back('"');
|
|
break;
|
|
case '\'':
|
|
ret.push_back('\'');
|
|
break;
|
|
case '\\':
|
|
ret.push_back('\\');
|
|
break;
|
|
case 'x': {
|
|
i += 2;
|
|
if (i >= source.size()) {
|
|
return std::nullopt;
|
|
}
|
|
std::optional<char> c1 = FromHex(source[i - 1]);
|
|
std::optional<char> c2 = FromHex(source[i]);
|
|
if (c1 == std::nullopt || c2 == std::nullopt) {
|
|
return std::nullopt;
|
|
}
|
|
ret.push_back(16 * *c1 + *c2);
|
|
break;
|
|
}
|
|
case 'u': {
|
|
++i;
|
|
if (i >= source.size() || source[i] != '{') {
|
|
return std::nullopt;
|
|
}
|
|
unsigned int unicode_int = 0;
|
|
++i;
|
|
int original_i = i;
|
|
while (i < source.size() && source[i] != '}') {
|
|
std::optional<char> hex_val = FromHex(source[i]);
|
|
if (hex_val == std::nullopt) {
|
|
return std::nullopt;
|
|
}
|
|
unicode_int = unicode_int << 4;
|
|
unicode_int += hex_val.value();
|
|
++i;
|
|
if (i - original_i > 8) {
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
if (i >= source.size()) {
|
|
return std::nullopt;
|
|
}
|
|
if (i - original_i == 0) {
|
|
return std::nullopt;
|
|
}
|
|
char utf8_buf[4];
|
|
char* utf8_end = &utf8_buf[0];
|
|
if (!llvm::ConvertCodePointToUTF8(unicode_int, utf8_end)) {
|
|
return std::nullopt;
|
|
}
|
|
ret.append(utf8_buf, utf8_end - utf8_buf);
|
|
break;
|
|
}
|
|
case '\n':
|
|
if (!is_block_string) {
|
|
return std::nullopt;
|
|
}
|
|
break;
|
|
default:
|
|
// Unsupported.
|
|
return std::nullopt;
|
|
}
|
|
} else if (c == '\t') {
|
|
// Disallow non-` ` horizontal whitespace:
|
|
// https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/lexical_conventions/whitespace.md
|
|
// TODO: This doesn't handle unicode whitespace.
|
|
return std::nullopt;
|
|
} else {
|
|
ret.push_back(c);
|
|
}
|
|
++i;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
auto ParseBlockStringLiteral(llvm::StringRef source, const int hashtag_num)
|
|
-> ErrorOr<std::string> {
|
|
llvm::SmallVector<llvm::StringRef> lines;
|
|
source.split(lines, '\n', /*MaxSplit=*/-1, /*KeepEmpty=*/true);
|
|
if (lines.size() < 2) {
|
|
return Error("Too few lines");
|
|
}
|
|
|
|
llvm::StringRef first = lines[0];
|
|
if (!first.consume_front(TripleQuotes)) {
|
|
return Error("Should start with triple quotes: " + first);
|
|
}
|
|
first = first.rtrim(HorizontalWhitespaceChars);
|
|
// Remaining chars, if any, are a file type indicator.
|
|
if (first.find_first_of("\"#") != llvm::StringRef::npos ||
|
|
first.find_first_of(HorizontalWhitespaceChars) != llvm::StringRef::npos) {
|
|
return Error("Invalid characters in file type indicator: " + first);
|
|
}
|
|
|
|
llvm::StringRef last = lines[lines.size() - 1];
|
|
const size_t last_length = last.size();
|
|
last = last.ltrim(HorizontalWhitespaceChars);
|
|
const size_t indent = last_length - last.size();
|
|
if (last != TripleQuotes) {
|
|
return Error("Should end with triple quotes: " + last);
|
|
}
|
|
|
|
std::string parsed;
|
|
for (size_t i = 1; i < lines.size() - 1; ++i) {
|
|
llvm::StringRef line = lines[i];
|
|
const size_t first_non_ws =
|
|
line.find_first_not_of(HorizontalWhitespaceChars);
|
|
if (first_non_ws == llvm::StringRef::npos) {
|
|
// Empty or whitespace-only line.
|
|
line = "";
|
|
} else {
|
|
if (first_non_ws < indent) {
|
|
return Error("Wrong indent for line: " + line + ", expected " +
|
|
llvm::Twine(indent));
|
|
}
|
|
line = line.drop_front(indent).rtrim(HorizontalWhitespaceChars);
|
|
}
|
|
// Unescaping with \n appended to handle things like \\<newline>.
|
|
llvm::SmallVector<char> buffer;
|
|
std::optional<std::string> unescaped =
|
|
UnescapeStringLiteral((line + "\n").toStringRef(buffer), hashtag_num,
|
|
/*is_block_string=*/true);
|
|
if (!unescaped.has_value()) {
|
|
return Error("Invalid escaping in " + line);
|
|
}
|
|
// A \<newline> string collapses into nothing.
|
|
if (!unescaped->empty()) {
|
|
parsed.append(*unescaped);
|
|
}
|
|
}
|
|
return parsed;
|
|
}
|
|
|
|
auto StringRefContainsPointer(llvm::StringRef ref, const char* ptr) -> bool {
|
|
auto le = std::less_equal<>();
|
|
return le(ref.begin(), ptr) && le(ptr, ref.end());
|
|
}
|
|
|
|
} // namespace Carbon
|