Files
carbon-lang/migrate_cpp/rewriter_test.cpp
T
Jon Ross-Perkins 4d522c8e90 Finish making clang-tidy (mostly) work (again) and run -fix (#2312)
This does some more work to the run_clang_tidy.py wrapper script, and runs an example pass.

"again" because it's really the proto fuzzer changes that broke it, it had been working before.

"mostly" because there's still an issue within the proto fuzzer that it can't find "port/protobuf.h", i.e. https://github.com/google/libprotobuf-mutator/tree/master/port, but I'm still hesitant to add an include path there.
2022-10-18 15:48:17 -07:00

191 lines
6.8 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 "migrate_cpp/rewriter.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "clang/AST/ASTConsumer.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"
namespace Carbon::Testing {
namespace {
// Represents C++ source code with at most one region enclosed in $[[...]]$ as
// an annotated range.
class Annotations {
public:
explicit Annotations(llvm::StringRef annotated_source) {
size_t index = annotated_source.find("$[[");
if (index == llvm::StringRef::npos) {
source_code_ = std::string(annotated_source);
return;
}
start_ = index;
end_ = annotated_source.find("]]$", index);
CARBON_CHECK(end_ != llvm::StringRef::npos)
<< "Found `$[[` but no matching `]]$`";
source_code_ = (llvm::Twine(annotated_source.substr(0, start_)) +
annotated_source.substr(start_ + 3, end_ - start_ - 3) +
annotated_source.substr(end_ + 3))
.str();
// Update `end_` so that it is relative to the unannotated source (which
// means three characters earlier due to the `$[[` being removed.
end_ -= 3;
}
// Returns a view into the unannotated source.
auto source() const -> llvm::StringRef { return source_code_; }
// Returns the offsets in the file representing the annotated range if they
// exist and `{0, std::numeric_limits<size_t>::max()}` otherwise.
auto range() const -> std::pair<size_t, size_t> {
return std::pair(start_, end_);
}
private:
std::string source_code_;
size_t start_ = 0;
size_t end_ = std::numeric_limits<size_t>::max();
};
// Rewrites the `cpp_code`, return the Carbon equivalent. If the text has no
// source range annotated with $[[...]]$, the entire translation unit will be
// migrated and output. Otherwise, only the migrated output corresponding to the
// annotated range will be be output. No more than one range may be annoated at
// all.
//
// This annotation mechanism is useful in that it allows us to specifically test
// the migration associated with specific nodes even when they require some
// additional context that we do not wish to be covered by the test.
auto RewriteText(llvm::StringRef cpp_code) -> std::string {
std::string result;
Annotations annotated_cpp_code(cpp_code);
bool success = clang::tooling::runToolOnCodeWithArgs(
std::make_unique<MigrationAction>(result, annotated_cpp_code.range()),
annotated_cpp_code.source(), {}, "test.cc", "clang-tool",
std::make_shared<clang::PCHContainerOperations>(),
clang::tooling::FileContentMappings());
return success ? result : "";
}
TEST(Rewriter, BoolLiteral) {
EXPECT_EQ(RewriteText("bool x = $[[true]]$;"), "true");
EXPECT_EQ(RewriteText("bool x = $[[false]]$;"), "false");
}
TEST(Rewriter, IntegerLiteral) {
EXPECT_EQ(RewriteText("int x = $[[0]]$;"), "0");
EXPECT_EQ(RewriteText("int x = $[[1]]$;"), "1");
EXPECT_EQ(RewriteText("int x = $[[1234]]$;"), "1234");
EXPECT_EQ(RewriteText("int x = $[[12'34]]$;"), "12_34");
EXPECT_EQ(RewriteText("int x = $[[12'3'4]]$;"), "12_3_4");
}
TEST(Rewriter, SingleDeclaration) {
EXPECT_EQ(RewriteText("bool b;"), "var b: bool;\n");
EXPECT_EQ(RewriteText("int i;"), "var i: i32;\n");
EXPECT_EQ(RewriteText("const bool b = false;"), "let b: bool = false;\n");
EXPECT_EQ(RewriteText("const int i = 17;"), "let i: i32 = 17;\n");
EXPECT_EQ(RewriteText("bool const b = false;"), "let b: bool = false;\n");
EXPECT_EQ(RewriteText("int const i = 1234;"), "let i: i32 = 1234;\n");
}
TEST(Rewriter, Pointers) {
// TODO: Add tests for pointers-to-const when the syntax is nailed down.
EXPECT_EQ(RewriteText("bool b;\n"
"$[[bool *p = &b]]$;"),
"var p: bool* = &b");
EXPECT_EQ(RewriteText("bool b;\n"
"$[[bool * const p = &b]]$;"),
"let p: bool* = &b");
// Pointers and non-pointers on the same DeclStmt.
EXPECT_EQ(RewriteText("bool b, *p;\n"),
"var b: bool;\n"
"var p: bool*;\n");
EXPECT_EQ(RewriteText("bool b, *p = &b;\n"),
"var b: bool;\n"
"var p: bool* = &b;\n");
}
TEST(Rewriter, DeclarationComma) {
EXPECT_EQ(RewriteText("int x, y;"),
"var x: i32;\n"
"var y: i32;\n");
EXPECT_EQ(RewriteText("int x = 7, y;"),
"var x: i32 = 7;\n"
"var y: i32;\n");
EXPECT_EQ(RewriteText("const int x = 1, y = 2;"),
"let x: i32 = 1;\n"
"let y: i32 = 2;\n");
EXPECT_EQ(RewriteText("int const x = 1234, y = 5678;"),
"let x: i32 = 1234;\n"
"let y: i32 = 5678;\n");
}
TEST(Rewriter, FunctionDeclaration) {
// Function declarations and definitions returning void.
EXPECT_EQ(RewriteText("void f();"), "fn f() -> ();\n");
EXPECT_EQ(RewriteText("void f() {}"),
"fn f() -> () {\n"
"}\n");
// Function declarations and definitions returning int.
EXPECT_EQ(RewriteText("int f();"), "fn f() -> i32;\n");
EXPECT_EQ(RewriteText("int f() { return 0; }"),
"fn f() -> i32 {\n"
"return 0;\n"
"}\n");
// Function declarations and definitions with a single parameter.
EXPECT_EQ(RewriteText("int f(bool);"), "fn f(_: bool) -> i32;\n");
EXPECT_EQ(RewriteText("int f(bool b);"), "fn f(b: bool) -> i32;\n");
EXPECT_EQ(RewriteText("int f(bool) { return 0; }"),
"fn f(_: bool) -> i32 {\n"
"return 0;\n"
"}\n");
EXPECT_EQ(RewriteText("int f(bool b) { return 0; }"),
"fn f(b: bool) -> i32 {\n"
"return 0;\n"
"}\n");
// Function declarations and definitions with a multiple parameters.
EXPECT_EQ(RewriteText("int f(bool, int);"),
"fn f(_: bool, _: i32) -> i32;\n");
EXPECT_EQ(RewriteText("int f(bool b, int n);"),
"fn f(b: bool, n: i32) -> i32;\n");
EXPECT_EQ(RewriteText("int f(bool, int n) { return 0; }"),
"fn f(_: bool, n: i32) -> i32 {\n"
"return 0;\n"
"}\n");
EXPECT_EQ(RewriteText("int f(bool b, int n) { return 0; }"),
"fn f(b: bool, n: i32) -> i32 {\n"
"return 0;\n"
"}\n");
EXPECT_EQ(RewriteText("int f(bool b, int n = 3) { return n; }"),
"fn f(b: bool, n: i32 = 3) -> i32 {\n"
"return n;\n"
"}\n");
// Function declarations with trailing-return syntax.
EXPECT_EQ(RewriteText("auto f(bool b, int n = 3) -> int;"),
"fn f(b: bool, n: i32 = 3) -> i32;\n");
EXPECT_EQ(RewriteText("auto f(bool b, int n = 3) -> int { return n; }"),
"fn f(b: bool, n: i32 = 3) -> i32 {\n"
"return n;\n"
"}\n");
}
} // namespace
} // namespace Carbon::Testing