103 lines · cpp
1//===-- RecordTest.cpp ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang-include-cleaner/Types.h"10#include "clang/Basic/FileManager.h"11#include "clang/Basic/FileSystemOptions.h"12#include "clang/Tooling/Inclusions/StandardLibrary.h"13#include "llvm/ADT/IntrusiveRefCntPtr.h"14#include "llvm/Support/VirtualFileSystem.h"15#include "gmock/gmock.h"16#include "gtest/gtest.h"17 18namespace clang::include_cleaner {19namespace {20using testing::ElementsAre;21using testing::IsEmpty;22using testing::UnorderedElementsAre;23 24// Matches an Include* on the specified line;25MATCHER_P(line, N, "") { return arg->Line == (unsigned)N; }26 27TEST(RecordedIncludesTest, Match) {28 // We're using synthetic data, but need a FileManager to obtain FileEntry*s.29 // Ensure it doesn't do any actual IO.30 auto FS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();31 FileManager FM(FileSystemOptions{});32 FileEntryRef A = FM.getVirtualFileRef("/path/a", /*Size=*/0, time_t{});33 FileEntryRef B = FM.getVirtualFileRef("/path/b", /*Size=*/0, time_t{});34 35 Includes Inc;36 Inc.add(Include{"a", A, SourceLocation(), 1});37 Inc.add(Include{"a2", A, SourceLocation(), 2});38 Inc.add(Include{"b", B, SourceLocation(), 3});39 Inc.add(Include{"vector", B, SourceLocation(), 4});40 Inc.add(Include{"vector", B, SourceLocation(), 5});41 Inc.add(Include{"missing", std::nullopt, SourceLocation(), 6});42 43 EXPECT_THAT(Inc.match(A), ElementsAre(line(1), line(2)));44 EXPECT_THAT(Inc.match(B), ElementsAre(line(3), line(4), line(5)));45 EXPECT_THAT(Inc.match(*tooling::stdlib::Header::named("<vector>")),46 ElementsAre(line(4), line(5)));47}48 49TEST(RecordedIncludesTest, MatchVerbatim) {50 auto FS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();51 FileManager FM(FileSystemOptions{});52 Includes Inc;53 54 // By default, a verbatim header only matches includes with the same spelling.55 auto Foo =56 FM.getVirtualFileRef("repo/lib/include/rel/foo.h", /*Size=*/0, time_t{});57 Inc.add(Include{"lib/include/rel/foo.h", Foo, SourceLocation(), 1});58 Inc.add(Include{"rel/foo.h", Foo, SourceLocation(), 2});59 EXPECT_THAT(Inc.match(Header("<rel/foo.h>")), ElementsAre(line(2)));60 61 // A verbatim header can match another spelling if the search path62 // suggests it's equivalent.63 auto Bar =64 FM.getVirtualFileRef("repo/lib/include/rel/bar.h", /*Size=*/0, time_t{});65 Inc.addSearchDirectory("repo/");66 Inc.addSearchDirectory("repo/lib/include");67 Inc.add(Include{"lib/include/rel/bar.h", Bar, SourceLocation(), 3});68 Inc.add(Include{"rel/bar.h", Bar, SourceLocation(), 4});69 EXPECT_THAT(Inc.match(Header("<rel/bar.h>")),70 UnorderedElementsAre(line(3), line(4)));71 72 // We don't apply this logic to system headers, though.73 auto Vector =74 FM.getVirtualFileRef("repo/lib/include/vector", /*Size=*/0, time_t{});75 Inc.add(Include{"lib/include/vector", Vector, SourceLocation(), 5});76 EXPECT_THAT(Inc.match(Header(*tooling::stdlib::Header::named("<vector>"))),77 IsEmpty());78}79 80TEST(RecordedIncludesTest, MatchVerbatimMixedAbsoluteRelative) {81 auto FS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();82 FS->setCurrentWorkingDirectory("/working");83 FileManager FM(FileSystemOptions{});84 Includes Inc;85 86 auto Foo =87 FM.getVirtualFileRef("/working/rel1/rel2/foo.h", /*Size=*/0, time_t{});88 Inc.addSearchDirectory("rel1");89 Inc.addSearchDirectory("rel1/rel2");90 Inc.add(Include{"rel2/foo.h", Foo, SourceLocation(), 1});91 EXPECT_THAT(Inc.match(Header("<foo.h>")), IsEmpty());92 93 Inc = Includes{};94 auto Bar = FM.getVirtualFileRef("rel1/rel2/bar.h", /*Size=*/0, time_t{});95 Inc.addSearchDirectory("/working/rel1");96 Inc.addSearchDirectory("/working/rel1/rel2");97 Inc.add(Include{"rel2/bar.h", Bar, SourceLocation(), 1});98 EXPECT_THAT(Inc.match(Header("<bar.h>")), IsEmpty());99}100 101} // namespace102} // namespace clang::include_cleaner103