1c28506baSViktoriia Bakalova //===--- IncludeCleanerTest.cpp - clang-tidy -----------------------------===// 2c28506baSViktoriia Bakalova // 3c28506baSViktoriia Bakalova // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4c28506baSViktoriia Bakalova // See https://llvm.org/LICENSE.txt for license information. 5c28506baSViktoriia Bakalova // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6c28506baSViktoriia Bakalova // 7c28506baSViktoriia Bakalova //===----------------------------------------------------------------------===// 8c28506baSViktoriia Bakalova 9c28506baSViktoriia Bakalova #include "ClangTidyDiagnosticConsumer.h" 10c28506baSViktoriia Bakalova #include "ClangTidyOptions.h" 11c28506baSViktoriia Bakalova #include "ClangTidyTest.h" 12c28506baSViktoriia Bakalova #include "misc/IncludeCleanerCheck.h" 13c28506baSViktoriia Bakalova #include "llvm/ADT/SmallString.h" 14c28506baSViktoriia Bakalova #include "llvm/ADT/StringRef.h" 15c28506baSViktoriia Bakalova #include "llvm/Support/FormatVariadic.h" 16c28506baSViktoriia Bakalova #include "llvm/Support/Path.h" 17c28506baSViktoriia Bakalova #include "llvm/Support/Regex.h" 1889d0a76bSKadir Cetinkaya #include "llvm/Testing/Annotations/Annotations.h" 1989d0a76bSKadir Cetinkaya #include "gmock/gmock.h" 20c28506baSViktoriia Bakalova #include "gtest/gtest.h" 21c28506baSViktoriia Bakalova #include <initializer_list> 22c28506baSViktoriia Bakalova 23c28506baSViktoriia Bakalova #include <optional> 24c28506baSViktoriia Bakalova #include <vector> 25c28506baSViktoriia Bakalova 26c28506baSViktoriia Bakalova using namespace clang::tidy::misc; 27c28506baSViktoriia Bakalova 28c28506baSViktoriia Bakalova namespace clang { 29c28506baSViktoriia Bakalova namespace tidy { 30c28506baSViktoriia Bakalova namespace test { 31c28506baSViktoriia Bakalova namespace { 32c28506baSViktoriia Bakalova 33c28506baSViktoriia Bakalova std::string 34c28506baSViktoriia Bakalova appendPathFileSystemIndependent(std::initializer_list<std::string> Segments) { 35c28506baSViktoriia Bakalova llvm::SmallString<32> Result; 36c28506baSViktoriia Bakalova for (const auto &Segment : Segments) 37c28506baSViktoriia Bakalova llvm::sys::path::append(Result, llvm::sys::path::Style::native, Segment); 38c28506baSViktoriia Bakalova return std::string(Result.str()); 39c28506baSViktoriia Bakalova } 40c28506baSViktoriia Bakalova 41c28506baSViktoriia Bakalova TEST(IncludeCleanerCheckTest, BasicUnusedIncludes) { 42c28506baSViktoriia Bakalova const char *PreCode = R"( 43c28506baSViktoriia Bakalova #include "bar.h" 44c28506baSViktoriia Bakalova #include <vector> 45c28506baSViktoriia Bakalova #include "bar.h" 46c28506baSViktoriia Bakalova )"; 47c28506baSViktoriia Bakalova const char *PostCode = "\n"; 48c28506baSViktoriia Bakalova 49c28506baSViktoriia Bakalova std::vector<ClangTidyError> Errors; 50d3cfc712Skadir çetinkaya EXPECT_EQ(PostCode, 51d3cfc712Skadir çetinkaya runCheckOnCode<IncludeCleanerCheck>( 52fc5de0afSJay Foad PreCode, &Errors, "file.cpp", {}, ClangTidyOptions(), 53d3cfc712Skadir çetinkaya {{"bar.h", "#pragma once"}, {"vector", "#pragma once"}})); 54c28506baSViktoriia Bakalova } 55c28506baSViktoriia Bakalova 56c28506baSViktoriia Bakalova TEST(IncludeCleanerCheckTest, SuppressUnusedIncludes) { 57c28506baSViktoriia Bakalova const char *PreCode = R"( 58c28506baSViktoriia Bakalova #include "bar.h" 59c28506baSViktoriia Bakalova #include "foo/qux.h" 60c28506baSViktoriia Bakalova #include "baz/qux/qux.h" 61c28506baSViktoriia Bakalova #include <vector> 6277feba5aSkadir çetinkaya #include <list> 63c28506baSViktoriia Bakalova )"; 64c28506baSViktoriia Bakalova 65c28506baSViktoriia Bakalova const char *PostCode = R"( 66c28506baSViktoriia Bakalova #include "bar.h" 67c28506baSViktoriia Bakalova #include "foo/qux.h" 68c28506baSViktoriia Bakalova #include <vector> 6977feba5aSkadir çetinkaya #include <list> 70c28506baSViktoriia Bakalova )"; 71c28506baSViktoriia Bakalova 72c28506baSViktoriia Bakalova std::vector<ClangTidyError> Errors; 73c28506baSViktoriia Bakalova ClangTidyOptions Opts; 74*222dd235SCongcong Cai Opts.CheckOptions["test-check-0.IgnoreHeaders"] = llvm::StringRef{ 75*222dd235SCongcong Cai llvm::formatv("bar.h;{0};{1};vector;<list>;", 76*222dd235SCongcong Cai llvm::Regex::escape( 77*222dd235SCongcong Cai appendPathFileSystemIndependent({"foo", "qux.h"})), 78*222dd235SCongcong Cai llvm::Regex::escape( 79*222dd235SCongcong Cai appendPathFileSystemIndependent({"baz", "qux"})))}; 80c28506baSViktoriia Bakalova EXPECT_EQ( 81c28506baSViktoriia Bakalova PostCode, 82c28506baSViktoriia Bakalova runCheckOnCode<IncludeCleanerCheck>( 83fc5de0afSJay Foad PreCode, &Errors, "file.cpp", {}, Opts, 84d3cfc712Skadir çetinkaya {{"bar.h", "#pragma once"}, 85d3cfc712Skadir çetinkaya {"vector", "#pragma once"}, 8677feba5aSkadir çetinkaya {"list", "#pragma once"}, 87d3cfc712Skadir çetinkaya {appendPathFileSystemIndependent({"foo", "qux.h"}), "#pragma once"}, 88d3cfc712Skadir çetinkaya {appendPathFileSystemIndependent({"baz", "qux", "qux.h"}), 89d3cfc712Skadir çetinkaya "#pragma once"}})); 90c28506baSViktoriia Bakalova } 91c28506baSViktoriia Bakalova 92c28506baSViktoriia Bakalova TEST(IncludeCleanerCheckTest, BasicMissingIncludes) { 93c28506baSViktoriia Bakalova const char *PreCode = R"( 94c28506baSViktoriia Bakalova #include "bar.h" 95c28506baSViktoriia Bakalova 96c28506baSViktoriia Bakalova int BarResult = bar(); 97c28506baSViktoriia Bakalova int BazResult = baz(); 98c28506baSViktoriia Bakalova )"; 99c28506baSViktoriia Bakalova const char *PostCode = R"( 100c28506baSViktoriia Bakalova #include "bar.h" 101c28506baSViktoriia Bakalova #include "baz.h" 102c28506baSViktoriia Bakalova 103c28506baSViktoriia Bakalova int BarResult = bar(); 104c28506baSViktoriia Bakalova int BazResult = baz(); 105c28506baSViktoriia Bakalova )"; 106c28506baSViktoriia Bakalova 107c28506baSViktoriia Bakalova std::vector<ClangTidyError> Errors; 108fc5de0afSJay Foad EXPECT_EQ(PostCode, runCheckOnCode<IncludeCleanerCheck>( 109fc5de0afSJay Foad PreCode, &Errors, "file.cpp", {}, ClangTidyOptions(), 110c28506baSViktoriia Bakalova {{"bar.h", R"(#pragma once 111c28506baSViktoriia Bakalova #include "baz.h" 112c28506baSViktoriia Bakalova int bar(); 113c28506baSViktoriia Bakalova )"}, 114c28506baSViktoriia Bakalova {"baz.h", R"(#pragma once 115c28506baSViktoriia Bakalova int baz(); 116c28506baSViktoriia Bakalova )"}})); 117c28506baSViktoriia Bakalova } 118c28506baSViktoriia Bakalova 11989d0a76bSKadir Cetinkaya TEST(IncludeCleanerCheckTest, DedupsMissingIncludes) { 12089d0a76bSKadir Cetinkaya llvm::Annotations Code(R"( 12189d0a76bSKadir Cetinkaya #include "baz.h" // IWYU pragma: keep 12289d0a76bSKadir Cetinkaya 12389d0a76bSKadir Cetinkaya int BarResult1 = $diag1^bar(); 12489d0a76bSKadir Cetinkaya int BarResult2 = $diag2^bar();)"); 12589d0a76bSKadir Cetinkaya 12689d0a76bSKadir Cetinkaya { 12789d0a76bSKadir Cetinkaya std::vector<ClangTidyError> Errors; 128fc5de0afSJay Foad runCheckOnCode<IncludeCleanerCheck>(Code.code(), &Errors, "file.cpp", {}, 129fc5de0afSJay Foad ClangTidyOptions(), 13089d0a76bSKadir Cetinkaya {{"baz.h", R"(#pragma once 13189d0a76bSKadir Cetinkaya #include "bar.h" 13289d0a76bSKadir Cetinkaya )"}, 13389d0a76bSKadir Cetinkaya {"bar.h", R"(#pragma once 13489d0a76bSKadir Cetinkaya int bar(); 13589d0a76bSKadir Cetinkaya )"}}); 13689d0a76bSKadir Cetinkaya ASSERT_THAT(Errors.size(), testing::Eq(1U)); 13789d0a76bSKadir Cetinkaya EXPECT_EQ(Errors.front().Message.Message, 13889d0a76bSKadir Cetinkaya "no header providing \"bar\" is directly included"); 13989d0a76bSKadir Cetinkaya EXPECT_EQ(Errors.front().Message.FileOffset, Code.point("diag1")); 14089d0a76bSKadir Cetinkaya } 14189d0a76bSKadir Cetinkaya { 14289d0a76bSKadir Cetinkaya std::vector<ClangTidyError> Errors; 14389d0a76bSKadir Cetinkaya ClangTidyOptions Opts; 144*222dd235SCongcong Cai Opts.CheckOptions["test-check-0.DeduplicateFindings"] = "false"; 145fc5de0afSJay Foad runCheckOnCode<IncludeCleanerCheck>(Code.code(), &Errors, "file.cpp", {}, 146fc5de0afSJay Foad Opts, 14789d0a76bSKadir Cetinkaya {{"baz.h", R"(#pragma once 14889d0a76bSKadir Cetinkaya #include "bar.h" 14989d0a76bSKadir Cetinkaya )"}, 15089d0a76bSKadir Cetinkaya {"bar.h", R"(#pragma once 15189d0a76bSKadir Cetinkaya int bar(); 15289d0a76bSKadir Cetinkaya )"}}); 15389d0a76bSKadir Cetinkaya ASSERT_THAT(Errors.size(), testing::Eq(2U)); 15489d0a76bSKadir Cetinkaya EXPECT_EQ(Errors.front().Message.Message, 15589d0a76bSKadir Cetinkaya "no header providing \"bar\" is directly included"); 15689d0a76bSKadir Cetinkaya EXPECT_EQ(Errors.front().Message.FileOffset, Code.point("diag1")); 15789d0a76bSKadir Cetinkaya EXPECT_EQ(Errors.back().Message.Message, 15889d0a76bSKadir Cetinkaya "no header providing \"bar\" is directly included"); 15989d0a76bSKadir Cetinkaya EXPECT_EQ(Errors.back().Message.FileOffset, Code.point("diag2")); 16089d0a76bSKadir Cetinkaya } 16189d0a76bSKadir Cetinkaya } 16289d0a76bSKadir Cetinkaya 163c28506baSViktoriia Bakalova TEST(IncludeCleanerCheckTest, SuppressMissingIncludes) { 164c28506baSViktoriia Bakalova const char *PreCode = R"( 165c28506baSViktoriia Bakalova #include "bar.h" 166c28506baSViktoriia Bakalova 167c28506baSViktoriia Bakalova int BarResult = bar(); 168c28506baSViktoriia Bakalova int BazResult = baz(); 169c28506baSViktoriia Bakalova int QuxResult = qux(); 17077feba5aSkadir çetinkaya int PrivResult = test(); 17177feba5aSkadir çetinkaya std::vector x; 172c28506baSViktoriia Bakalova )"; 173c28506baSViktoriia Bakalova 174c28506baSViktoriia Bakalova ClangTidyOptions Opts; 175*222dd235SCongcong Cai Opts.CheckOptions["test-check-0.IgnoreHeaders"] = llvm::StringRef{ 17677feba5aSkadir çetinkaya "public.h;<vector>;baz.h;" + 177c28506baSViktoriia Bakalova llvm::Regex::escape(appendPathFileSystemIndependent({"foo", "qux.h"}))}; 178c28506baSViktoriia Bakalova std::vector<ClangTidyError> Errors; 179c28506baSViktoriia Bakalova EXPECT_EQ(PreCode, runCheckOnCode<IncludeCleanerCheck>( 180fc5de0afSJay Foad PreCode, &Errors, "file.cpp", {}, Opts, 181c28506baSViktoriia Bakalova {{"bar.h", R"(#pragma once 182c28506baSViktoriia Bakalova #include "baz.h" 183c28506baSViktoriia Bakalova #include "foo/qux.h" 18477feba5aSkadir çetinkaya #include "private.h" 185c28506baSViktoriia Bakalova int bar(); 18677feba5aSkadir çetinkaya namespace std { struct vector {}; } 187c28506baSViktoriia Bakalova )"}, 188c28506baSViktoriia Bakalova {"baz.h", R"(#pragma once 189c28506baSViktoriia Bakalova int baz(); 190c28506baSViktoriia Bakalova )"}, 19177feba5aSkadir çetinkaya {"private.h", R"(#pragma once 19277feba5aSkadir çetinkaya // IWYU pragma: private, include "public.h" 19377feba5aSkadir çetinkaya int test(); 19477feba5aSkadir çetinkaya )"}, 195c28506baSViktoriia Bakalova {appendPathFileSystemIndependent({"foo", "qux.h"}), 196c28506baSViktoriia Bakalova R"(#pragma once 197c28506baSViktoriia Bakalova int qux(); 198c28506baSViktoriia Bakalova )"}})); 199c28506baSViktoriia Bakalova } 200c28506baSViktoriia Bakalova 201b0831c39SCongcong Cai TEST(IncludeCleanerCheckTest, MultipleTimeMissingInclude) { 202b0831c39SCongcong Cai const char *PreCode = R"( 203b0831c39SCongcong Cai #include "bar.h" 204b0831c39SCongcong Cai 205b0831c39SCongcong Cai int BarResult = bar(); 206b0831c39SCongcong Cai int BazResult_0 = baz_0(); 207b0831c39SCongcong Cai int BazResult_1 = baz_1(); 208b0831c39SCongcong Cai )"; 209b0831c39SCongcong Cai const char *PostCode = R"( 210b0831c39SCongcong Cai #include "bar.h" 211b0831c39SCongcong Cai #include "baz.h" 212b0831c39SCongcong Cai 213b0831c39SCongcong Cai int BarResult = bar(); 214b0831c39SCongcong Cai int BazResult_0 = baz_0(); 215b0831c39SCongcong Cai int BazResult_1 = baz_1(); 216b0831c39SCongcong Cai )"; 217b0831c39SCongcong Cai 218b0831c39SCongcong Cai std::vector<ClangTidyError> Errors; 219fc5de0afSJay Foad EXPECT_EQ(PostCode, runCheckOnCode<IncludeCleanerCheck>( 220fc5de0afSJay Foad PreCode, &Errors, "file.cpp", {}, ClangTidyOptions(), 221b0831c39SCongcong Cai {{"bar.h", R"(#pragma once 222b0831c39SCongcong Cai #include "baz.h" 223b0831c39SCongcong Cai int bar(); 224b0831c39SCongcong Cai )"}, 225b0831c39SCongcong Cai {"baz.h", R"(#pragma once 226b0831c39SCongcong Cai int baz_0(); 227b0831c39SCongcong Cai int baz_1(); 228b0831c39SCongcong Cai )"}})); 229b0831c39SCongcong Cai } 230b0831c39SCongcong Cai 231c28506baSViktoriia Bakalova TEST(IncludeCleanerCheckTest, SystemMissingIncludes) { 232c28506baSViktoriia Bakalova const char *PreCode = R"( 233c28506baSViktoriia Bakalova #include <vector> 234c28506baSViktoriia Bakalova 235c28506baSViktoriia Bakalova std::string HelloString; 236c28506baSViktoriia Bakalova std::vector Vec; 237c28506baSViktoriia Bakalova )"; 238c28506baSViktoriia Bakalova const char *PostCode = R"( 239c28506baSViktoriia Bakalova #include <string> 240c28506baSViktoriia Bakalova #include <vector> 241c28506baSViktoriia Bakalova 242c28506baSViktoriia Bakalova std::string HelloString; 243c28506baSViktoriia Bakalova std::vector Vec; 244c28506baSViktoriia Bakalova )"; 245c28506baSViktoriia Bakalova 246c28506baSViktoriia Bakalova std::vector<ClangTidyError> Errors; 247fc5de0afSJay Foad EXPECT_EQ(PostCode, runCheckOnCode<IncludeCleanerCheck>( 248fc5de0afSJay Foad PreCode, &Errors, "file.cpp", {}, ClangTidyOptions(), 249c28506baSViktoriia Bakalova {{"string", R"(#pragma once 250c28506baSViktoriia Bakalova namespace std { class string {}; } 251c28506baSViktoriia Bakalova )"}, 252c28506baSViktoriia Bakalova {"vector", R"(#pragma once 253c28506baSViktoriia Bakalova #include <string> 254c28506baSViktoriia Bakalova namespace std { class vector {}; } 255c28506baSViktoriia Bakalova )"}})); 256c28506baSViktoriia Bakalova } 257c28506baSViktoriia Bakalova 258c28506baSViktoriia Bakalova TEST(IncludeCleanerCheckTest, PragmaMissingIncludes) { 259c28506baSViktoriia Bakalova const char *PreCode = R"( 260c28506baSViktoriia Bakalova #include "bar.h" 261c28506baSViktoriia Bakalova 262c28506baSViktoriia Bakalova int BarResult = bar(); 263c28506baSViktoriia Bakalova int FooBarResult = foobar(); 264c28506baSViktoriia Bakalova )"; 265c28506baSViktoriia Bakalova const char *PostCode = R"( 266c28506baSViktoriia Bakalova #include "bar.h" 267c28506baSViktoriia Bakalova #include "public.h" 268c28506baSViktoriia Bakalova 269c28506baSViktoriia Bakalova int BarResult = bar(); 270c28506baSViktoriia Bakalova int FooBarResult = foobar(); 271c28506baSViktoriia Bakalova )"; 272c28506baSViktoriia Bakalova 273c28506baSViktoriia Bakalova std::vector<ClangTidyError> Errors; 274fc5de0afSJay Foad EXPECT_EQ(PostCode, runCheckOnCode<IncludeCleanerCheck>( 275fc5de0afSJay Foad PreCode, &Errors, "file.cpp", {}, ClangTidyOptions(), 276c28506baSViktoriia Bakalova {{"bar.h", R"(#pragma once 277c28506baSViktoriia Bakalova #include "private.h" 278c28506baSViktoriia Bakalova int bar(); 279c28506baSViktoriia Bakalova )"}, 280c28506baSViktoriia Bakalova {"private.h", R"(#pragma once 281c28506baSViktoriia Bakalova // IWYU pragma: private, include "public.h" 282c28506baSViktoriia Bakalova int foobar(); 283c28506baSViktoriia Bakalova )"}})); 284c28506baSViktoriia Bakalova } 285c28506baSViktoriia Bakalova 286c28506baSViktoriia Bakalova TEST(IncludeCleanerCheckTest, DeclFromMacroExpansion) { 287c28506baSViktoriia Bakalova const char *PreCode = R"( 288c28506baSViktoriia Bakalova #include "foo.h" 289c28506baSViktoriia Bakalova 290c28506baSViktoriia Bakalova DECLARE(myfunc) { 291c28506baSViktoriia Bakalova int a; 292c28506baSViktoriia Bakalova } 293c28506baSViktoriia Bakalova )"; 294c28506baSViktoriia Bakalova 295c28506baSViktoriia Bakalova std::vector<ClangTidyError> Errors; 296fc5de0afSJay Foad EXPECT_EQ(PreCode, runCheckOnCode<IncludeCleanerCheck>( 297fc5de0afSJay Foad PreCode, &Errors, "file.cpp", {}, ClangTidyOptions(), 298c28506baSViktoriia Bakalova {{"foo.h", 299c28506baSViktoriia Bakalova R"(#pragma once 300c28506baSViktoriia Bakalova #define DECLARE(X) void X() 301c28506baSViktoriia Bakalova )"}})); 302c28506baSViktoriia Bakalova 303c28506baSViktoriia Bakalova PreCode = R"( 304c28506baSViktoriia Bakalova #include "foo.h" 305c28506baSViktoriia Bakalova 306c28506baSViktoriia Bakalova DECLARE { 307c28506baSViktoriia Bakalova int a; 308c28506baSViktoriia Bakalova } 309c28506baSViktoriia Bakalova )"; 310c28506baSViktoriia Bakalova 311fc5de0afSJay Foad EXPECT_EQ(PreCode, runCheckOnCode<IncludeCleanerCheck>( 312fc5de0afSJay Foad PreCode, &Errors, "file.cpp", {}, ClangTidyOptions(), 313c28506baSViktoriia Bakalova {{"foo.h", 314c28506baSViktoriia Bakalova R"(#pragma once 315c28506baSViktoriia Bakalova #define DECLARE void myfunc() 316c28506baSViktoriia Bakalova )"}})); 317c28506baSViktoriia Bakalova } 318c28506baSViktoriia Bakalova 319c28506baSViktoriia Bakalova } // namespace 320c28506baSViktoriia Bakalova } // namespace test 321c28506baSViktoriia Bakalova } // namespace tidy 322c28506baSViktoriia Bakalova } // namespace clang 323