//===- NamespaceEndCommentsFixerTest.cpp - Formatting unit tests ----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Format/Format.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/Support/Debug.h"
#include "gtest/gtest.h"
#define DEBUG_TYPE "namespace-end-comments-fixer-test"
namespace clang {
namespace format {
namespace {
class NamespaceEndCommentsFixerTest : public ::testing::Test {
protected:
std::string
fixNamespaceEndComments(llvm::StringRef Code,
const std::vector<tooling::Range> &Ranges,
const FormatStyle &Style = getLLVMStyle()) {
LLVM_DEBUG(llvm::errs() << "---\n");
LLVM_DEBUG(llvm::errs() << Code << "\n\n");
tooling::Replacements Replaces =
clang::format::fixNamespaceEndComments(Style, Code, Ranges, "<stdin>");
auto Result = applyAllReplacements(Code, Replaces);
EXPECT_TRUE(static_cast<bool>(Result));
LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
return *Result;
}
std::string
fixNamespaceEndComments(llvm::StringRef Code,
const FormatStyle &Style = getLLVMStyle()) {
return fixNamespaceEndComments(
Code,
/*Ranges=*/{1, tooling::Range(0, Code.size())}, Style);
}
};
TEST_F(NamespaceEndCommentsFixerTest, AddsEndComment) {
EXPECT_EQ("namespace {\n"
" int i;\n"
" int j;\n"
"}// namespace",
fixNamespaceEndComments("namespace {\n"
" int i;\n"
" int j;\n"
"}"));
EXPECT_EQ("namespace {\n"
" int i;\n"
" int j;\n"
"}// namespace\n",
fixNamespaceEndComments("namespace {\n"
" int i;\n"
" int j;\n"
"}\n"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
" int j;\n"
"}// namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
" int j;\n"
"}"));
EXPECT_EQ("inline namespace A {\n"
" int i;\n"
" int j;\n"
"}// namespace A",
fixNamespaceEndComments("inline namespace A {\n"
" int i;\n"
" int j;\n"
"}"));
EXPECT_EQ("namespace ::A {\n"
" int i;\n"
" int j;\n"
"}// namespace ::A",
fixNamespaceEndComments("namespace ::A {\n"
" int i;\n"
" int j;\n"
"}"));
EXPECT_EQ("namespace ::A::B {\n"
" int i;\n"
" int j;\n"
"}// namespace ::A::B",
fixNamespaceEndComments("namespace ::A::B {\n"
" int i;\n"
" int j;\n"
"}"));
EXPECT_EQ("namespace /**/::/**/A/**/::/**/B/**/ {\n"
" int i;\n"
" int j;\n"
"}// namespace ::A::B",
fixNamespaceEndComments("namespace /**/::/**/A/**/::/**/B/**/ {\n"
" int i;\n"
" int j;\n"
"}"));
EXPECT_EQ("namespace A {\n"
"namespace B {\n"
" int i;\n"
"}\n"
"}// namespace A",
fixNamespaceEndComments("namespace A {\n"
"namespace B {\n"
" int i;\n"
"}\n"
"}"));
EXPECT_EQ("namespace A {\n"
"namespace B {\n"
" int i;\n"
" int j;\n"
"}// namespace B\n"
"}// namespace A",
fixNamespaceEndComments("namespace A {\n"
"namespace B {\n"
" int i;\n"
" int j;\n"
"}\n"
"}"));
EXPECT_EQ("namespace A {\n"
" int a;\n"
" int b;\n"
"}// namespace A\n"
"namespace B {\n"
" int b;\n"
" int a;\n"
"}// namespace B",
fixNamespaceEndComments("namespace A {\n"
" int a;\n"
" int b;\n"
"}\n"
"namespace B {\n"
" int b;\n"
" int a;\n"
"}"));
EXPECT_EQ("namespace A {\n"
" int a1;\n"
" int a2;\n"
"}// namespace A\n"
"namespace A {\n"
" int a2;\n"
" int a1;\n"
"}// namespace A",
fixNamespaceEndComments("namespace A {\n"
" int a1;\n"
" int a2;\n"
"}\n"
"namespace A {\n"
" int a2;\n"
" int a1;\n"
"}"));
EXPECT_EQ("namespace A {\n"
" int a;\n"
" int b;\n"
"}// namespace A\n"
"// comment about b\n"
"int b;",
fixNamespaceEndComments("namespace A {\n"
" int a;\n"
" int b;\n"
"}\n"
"// comment about b\n"
"int b;"));
EXPECT_EQ("namespace A {\n"
"namespace B {\n"
"namespace C {\n"
"namespace D {\n"
"}\n"
"}// namespace C\n"
"}// namespace B\n"
"}// namespace A",
fixNamespaceEndComments("namespace A {\n"
"namespace B {\n"
"namespace C {\n"
"namespace D {\n"
"}\n"
"}\n"
"}\n"
"}"));
// Add comment for namespaces which will be 'compacted'
FormatStyle CompactNamespacesStyle = getLLVMStyle();
CompactNamespacesStyle.CompactNamespaces = true;
EXPECT_EQ("namespace out { namespace in {\n"
"int i;\n"
"int j;\n"
"}}// namespace out::in",
fixNamespaceEndComments("namespace out { namespace in {\n"
"int i;\n"
"int j;\n"
"}}",
CompactNamespacesStyle));
EXPECT_EQ("namespace out {\n"
"namespace in {\n"
"int i;\n"
"int j;\n"
"}\n"
"}// namespace out::in",
fixNamespaceEndComments("namespace out {\n"
"namespace in {\n"
"int i;\n"
"int j;\n"
"}\n"
"}",
CompactNamespacesStyle));
EXPECT_EQ("namespace out { namespace in {\n"
"int i;\n"
"int j;\n"
"};}// namespace out::in",
fixNamespaceEndComments("namespace out { namespace in {\n"
"int i;\n"
"int j;\n"
"};}",
CompactNamespacesStyle));
// Adds an end comment after a semicolon.
EXPECT_EQ("namespace {\n"
" int i;\n"
" int j;\n"
"};// namespace",
fixNamespaceEndComments("namespace {\n"
" int i;\n"
" int j;\n"
"};"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
" int j;\n"
"};// namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
" int j;\n"
"};"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
" int j;\n"
"};// namespace A\n"
"// unrelated",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
" int j;\n"
"};\n"
"// unrelated"));
}
TEST_F(NamespaceEndCommentsFixerTest, AddsNewlineIfNeeded) {
EXPECT_EQ("namespace A {\n"
" int i;\n"
" int j;\n"
"}// namespace A\n"
" int k;",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
" int j;\n"
"} int k;"));
EXPECT_EQ("namespace {\n"
" int i;\n"
" int j;\n"
"}// namespace\n"
" int k;",
fixNamespaceEndComments("namespace {\n"
" int i;\n"
" int j;\n"
"} int k;"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
" int j;\n"
"}// namespace A\n"
" namespace B {\n"
" int j;\n"
" int k;\n"
"}// namespace B",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
" int j;\n"
"} namespace B {\n"
" int j;\n"
" int k;\n"
"}"));
EXPECT_EQ("namespace {\n"
" int i;\n"
" int j;\n"
"};// namespace\n"
"int k;",
fixNamespaceEndComments("namespace {\n"
" int i;\n"
" int j;\n"
"};int k;"));
EXPECT_EQ("namespace {\n"
" int i;\n"
" int j;\n"
"};// namespace\n"
";",
fixNamespaceEndComments("namespace {\n"
" int i;\n"
" int j;\n"
"};;"));
}
TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddEndCommentForShortNamespace) {
EXPECT_EQ("namespace {}", fixNamespaceEndComments("namespace {}"));
EXPECT_EQ("namespace A {}", fixNamespaceEndComments("namespace A {}"));
EXPECT_EQ("namespace A { a }",
fixNamespaceEndComments("namespace A { a }"));
EXPECT_EQ("namespace A { a };",
fixNamespaceEndComments("namespace A { a };"));
}
TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddCommentAfterUnaffectedRBrace) {
EXPECT_EQ("namespace A {\n"
" int i;\n"
"}",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"}",
// The range (16, 3) spans the 'int' above.
/*Ranges=*/{1, tooling::Range(16, 3)}));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"};",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"};",
// The range (16, 3) spans the 'int' above.
/*Ranges=*/{1, tooling::Range(16, 3)}));
}
TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddCommentAfterRBraceInPPDirective) {
EXPECT_EQ("#define SAD \\\n"
"namespace A { \\\n"
" int i; \\\n"
"}",
fixNamespaceEndComments("#define SAD \\\n"
"namespace A { \\\n"
" int i; \\\n"
"}"));
}
TEST_F(NamespaceEndCommentsFixerTest, KeepsValidEndComment) {
EXPECT_EQ("namespace {\n"
" int i;\n"
"} // end anonymous namespace",
fixNamespaceEndComments("namespace {\n"
" int i;\n"
"} // end anonymous namespace"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"} /* end of namespace A */",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"} /* end of namespace A */"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"} // namespace A"));
EXPECT_EQ("namespace A::B {\n"
" int i;\n"
"} // end namespace A::B",
fixNamespaceEndComments("namespace A::B {\n"
" int i;\n"
"} // end namespace A::B"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"}; // end namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"}; // end namespace A"));
EXPECT_EQ("namespace {\n"
" int i;\n"
"}; /* unnamed namespace */",
fixNamespaceEndComments("namespace {\n"
" int i;\n"
"}; /* unnamed namespace */"));
}
TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndLineComment) {
EXPECT_EQ("namespace {\n"
" int i;\n"
"} // namespace",
fixNamespaceEndComments("namespace {\n"
" int i;\n"
"} // namespace A"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"} // namespace"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"} //"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"} //"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"} // banamespace A"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"}; // namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"}; // banamespace A"));
// Updates invalid line comments even for short namespaces.
EXPECT_EQ("namespace A {} // namespace A",
fixNamespaceEndComments("namespace A {} // namespace"));
EXPECT_EQ("namespace A {}; // namespace A",
fixNamespaceEndComments("namespace A {}; // namespace"));
// Update invalid comments for compacted namespaces.
FormatStyle CompactNamespacesStyle = getLLVMStyle();
CompactNamespacesStyle.CompactNamespaces = true;
EXPECT_EQ("namespace out { namespace in {\n"
"}} // namespace out::in",
fixNamespaceEndComments("namespace out { namespace in {\n"
"}} // namespace out",
CompactNamespacesStyle));
EXPECT_EQ("namespace out { namespace in {\n"
"}} // namespace out::in",
fixNamespaceEndComments("namespace out { namespace in {\n"
"}} // namespace in",
CompactNamespacesStyle));
EXPECT_EQ("namespace out { namespace in {\n"
"}\n"
"} // namespace out::in",
fixNamespaceEndComments("namespace out { namespace in {\n"
"}// banamespace in\n"
"} // namespace out",
CompactNamespacesStyle));
}
TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndBlockComment) {
EXPECT_EQ("namespace {\n"
" int i;\n"
"} // namespace",
fixNamespaceEndComments("namespace {\n"
" int i;\n"
"} /* namespace A */"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"} /* end namespace */"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"} /**/"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"} /* end unnamed namespace */"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"} /* banamespace A */"));
EXPECT_EQ("namespace A {\n"
" int i;\n"
"}; // namespace A",
fixNamespaceEndComments("namespace A {\n"
" int i;\n"
"}; /* banamespace A */"));
EXPECT_EQ("namespace A {} // namespace A",
fixNamespaceEndComments("namespace A {} /**/"));
EXPECT_EQ("namespace A {}; // namespace A",
fixNamespaceEndComments("namespace A {}; /**/"));
}
TEST_F(NamespaceEndCommentsFixerTest,
DoesNotAddEndCommentForNamespacesControlledByMacros) {
EXPECT_EQ("#ifdef 1\n"
"namespace A {\n"
"#elseif\n"
"namespace B {\n"
"#endif\n"
" int i;\n"
"}\n"
"}\n",
fixNamespaceEndComments("#ifdef 1\n"
"namespace A {\n"
"#elseif\n"
"namespace B {\n"
"#endif\n"
" int i;\n"
"}\n"
"}\n"));
}
TEST_F(NamespaceEndCommentsFixerTest, AddEndCommentForNamespacesAroundMacros) {
// Conditional blocks around are fine
EXPECT_EQ("namespace A {\n"
"#if 1\n"
"int i;\n"
"#endif\n"
"}// namespace A",
fixNamespaceEndComments("namespace A {\n"
"#if 1\n"
"int i;\n"
"#endif\n"
"}"));
EXPECT_EQ("#if 1\n"
"#endif\n"
"namespace A {\n"
"int i;\n"
"int j;\n"
"}// namespace A",
fixNamespaceEndComments("#if 1\n"
"#endif\n"
"namespace A {\n"
"int i;\n"
"int j;\n"
"}"));
EXPECT_EQ("namespace A {\n"
"int i;\n"
"int j;\n"
"}// namespace A\n"
"#if 1\n"
"#endif",
fixNamespaceEndComments("namespace A {\n"
"int i;\n"
"int j;\n"
"}\n"
"#if 1\n"
"#endif"));
EXPECT_EQ("#if 1\n"
"namespace A {\n"
"int i;\n"
"int j;\n"
"}// namespace A\n"
"#endif",
fixNamespaceEndComments("#if 1\n"
"namespace A {\n"
"int i;\n"
"int j;\n"
"}\n"
"#endif"));
// Macro definition has no impact
EXPECT_EQ("namespace A {\n"
"#define FOO\n"
"int i;\n"
"}// namespace A",
fixNamespaceEndComments("namespace A {\n"
"#define FOO\n"
"int i;\n"
"}"));
EXPECT_EQ("#define FOO\n"
"namespace A {\n"
"int i;\n"
"int j;\n"
"}// namespace A",
fixNamespaceEndComments("#define FOO\n"
"namespace A {\n"
"int i;\n"
"int j;\n"
"}"));
EXPECT_EQ("namespace A {\n"
"int i;\n"
"int j;\n"
"}// namespace A\n"
"#define FOO\n",
fixNamespaceEndComments("namespace A {\n"
"int i;\n"
"int j;\n"
"}\n"
"#define FOO\n"));
// No replacement if open & close in different conditional blocks
EXPECT_EQ("#if 1\n"
"namespace A {\n"
"#endif\n"
"int i;\n"
"int j;\n"
"#if 1\n"
"}\n"
"#endif",
fixNamespaceEndComments("#if 1\n"
"namespace A {\n"
"#endif\n"
"int i;\n"
"int j;\n"
"#if 1\n"
"}\n"
"#endif"));
EXPECT_EQ("#ifdef A\n"
"namespace A {\n"
"#endif\n"
"int i;\n"
"int j;\n"
"#ifdef B\n"
"}\n"
"#endif",
fixNamespaceEndComments("#ifdef A\n"
"namespace A {\n"
"#endif\n"
"int i;\n"
"int j;\n"
"#ifdef B\n"
"}\n"
"#endif"));
// No replacement inside unreachable conditional block
EXPECT_EQ("#if 0\n"
"namespace A {\n"
"int i;\n"
"int j;\n"
"}\n"
"#endif",
fixNamespaceEndComments("#if 0\n"
"namespace A {\n"
"int i;\n"
"int j;\n"
"}\n"
"#endif"));
}
TEST_F(NamespaceEndCommentsFixerTest,
DoesNotAddEndCommentForNamespacesInMacroDeclarations) {
EXPECT_EQ("#ifdef 1\n"
"namespace A {\n"
"#elseif\n"
"namespace B {\n"
"#endif\n"
" int i;\n"
"}\n"
"}\n",
fixNamespaceEndComments("#ifdef 1\n"
"namespace A {\n"
"#elseif\n"
"namespace B {\n"
"#endif\n"
" int i;\n"
"}\n"
"}\n"));
EXPECT_EQ("namespace {\n"
" int i;\n"
" int j;\n"
"}// namespace\n"
"#if A\n"
" int i;\n"
"#else\n"
" int j;\n"
"#endif",
fixNamespaceEndComments("namespace {\n"
" int i;\n"
" int j;\n"
"}\n"
"#if A\n"
" int i;\n"
"#else\n"
" int j;\n"
"#endif"));
EXPECT_EQ("#if A\n"
"namespace A {\n"
"#else\n"
"namespace B {\n"
"#endif\n"
"int i;\n"
"int j;\n"
"}",
fixNamespaceEndComments("#if A\n"
"namespace A {\n"
"#else\n"
"namespace B {\n"
"#endif\n"
"int i;\n"
"int j;\n"
"}"));
EXPECT_EQ("#if A\n"
"namespace A {\n"
"#else\n"
"namespace B {\n"
"#endif\n"
"int i;\n"
"int j;\n"
"} // namespace A",
fixNamespaceEndComments("#if A\n"
"namespace A {\n"
"#else\n"
"namespace B {\n"
"#endif\n"
"int i;\n"
"int j;\n"
"} // namespace A"));
EXPECT_EQ("#if A\n"
"namespace A {\n"
"#else\n"
"namespace B {\n"
"#endif\n"
"int i;\n"
"int j;\n"
"} // namespace B",
fixNamespaceEndComments("#if A\n"
"namespace A {\n"
"#else\n"
"namespace B {\n"
"#endif\n"
"int i;\n"
"int j;\n"
"} // namespace B"));
EXPECT_EQ("namespace A\n"
"int i;\n"
"int j;\n"
"#if A\n"
"}\n"
"#else\n"
"}\n"
"#endif",
fixNamespaceEndComments("namespace A\n"
"int i;\n"
"int j;\n"
"#if A\n"
"}\n"
"#else\n"
"}\n"
"#endif"));
EXPECT_EQ("namespace A\n"
"int i;\n"
"int j;\n"
"#if A\n"
"} // namespace A\n"
"#else\n"
"} // namespace A\n"
"#endif",
fixNamespaceEndComments("namespace A\n"
"int i;\n"
"int j;\n"
"#if A\n"
"} // namespace A\n"
"#else\n"
"} // namespace A\n"
"#endif"));
}
TEST_F(NamespaceEndCommentsFixerTest,
DoesNotAddEndCommentForUnbalancedRBracesAfterNamespaceEnd) {
EXPECT_EQ("namespace {\n"
" int i;\n"
"} // namespace\n"
"}",
fixNamespaceEndComments("namespace {\n"
" int i;\n"
"} // namespace\n"
"}"));
}
TEST_F(NamespaceEndCommentsFixerTest, HandlesInlineAtEndOfLine_PR32438) {
EXPECT_EQ("template <int> struct a {};\n"
"struct a<bool{}> b() {\n"
"}\n"
"#define c inline\n"
"void d() {\n"
"}\n",
fixNamespaceEndComments("template <int> struct a {};\n"
"struct a<bool{}> b() {\n"
"}\n"
"#define c inline\n"
"void d() {\n"
"}\n"));
}
} // end namespace
} // end namespace format
} // end namespace clang