diff options
Diffstat (limited to 'unittests/CrossTU/CrossTranslationUnitTest.cpp')
-rw-r--r-- | unittests/CrossTU/CrossTranslationUnitTest.cpp | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/unittests/CrossTU/CrossTranslationUnitTest.cpp b/unittests/CrossTU/CrossTranslationUnitTest.cpp new file mode 100644 index 000000000000..5fbf56ed43b8 --- /dev/null +++ b/unittests/CrossTU/CrossTranslationUnitTest.cpp @@ -0,0 +1,158 @@ +//===- unittest/Tooling/CrossTranslationUnitTest.cpp - Tooling 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/CrossTU/CrossTranslationUnit.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/ToolOutputFile.h" +#include "gtest/gtest.h" +#include <cassert> + +namespace clang { +namespace cross_tu { + +namespace { + +class CTUASTConsumer : public clang::ASTConsumer { +public: + explicit CTUASTConsumer(clang::CompilerInstance &CI, bool *Success) + : CTU(CI), Success(Success) {} + + void HandleTranslationUnit(ASTContext &Ctx) { + const TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl(); + const FunctionDecl *FD = nullptr; + for (const Decl *D : TU->decls()) { + FD = dyn_cast<FunctionDecl>(D); + if (FD && FD->getName() == "f") + break; + } + assert(FD && FD->getName() == "f"); + bool OrigFDHasBody = FD->hasBody(); + + // Prepare the index file and the AST file. + int ASTFD; + llvm::SmallString<256> ASTFileName; + ASSERT_FALSE( + llvm::sys::fs::createTemporaryFile("f_ast", "ast", ASTFD, ASTFileName)); + llvm::ToolOutputFile ASTFile(ASTFileName, ASTFD); + + int IndexFD; + llvm::SmallString<256> IndexFileName; + ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD, + IndexFileName)); + llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD); + IndexFile.os() << "c:@F@f#I# " << ASTFileName << "\n"; + IndexFile.os().flush(); + EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName)); + + StringRef SourceText = "int f(int) { return 0; }\n"; + // This file must exist since the saved ASTFile will reference it. + int SourceFD; + llvm::SmallString<256> SourceFileName; + ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("input", "cpp", SourceFD, + SourceFileName)); + llvm::ToolOutputFile SourceFile(SourceFileName, SourceFD); + SourceFile.os() << SourceText; + SourceFile.os().flush(); + EXPECT_TRUE(llvm::sys::fs::exists(SourceFileName)); + + std::unique_ptr<ASTUnit> ASTWithDefinition = + tooling::buildASTFromCode(SourceText, SourceFileName); + ASTWithDefinition->Save(ASTFileName.str()); + EXPECT_TRUE(llvm::sys::fs::exists(ASTFileName)); + + // Load the definition from the AST file. + llvm::Expected<const FunctionDecl *> NewFDorError = + CTU.getCrossTUDefinition(FD, "", IndexFileName); + EXPECT_TRUE((bool)NewFDorError); + const FunctionDecl *NewFD = *NewFDorError; + + *Success = NewFD && NewFD->hasBody() && !OrigFDHasBody; + } + +private: + CrossTranslationUnitContext CTU; + bool *Success; +}; + +class CTUAction : public clang::ASTFrontendAction { +public: + CTUAction(bool *Success) : Success(Success) {} + +protected: + std::unique_ptr<clang::ASTConsumer> + CreateASTConsumer(clang::CompilerInstance &CI, StringRef) override { + return llvm::make_unique<CTUASTConsumer>(CI, Success); + } + +private: + bool *Success; +}; + +} // end namespace + +TEST(CrossTranslationUnit, CanLoadFunctionDefinition) { + bool Success = false; + EXPECT_TRUE(tooling::runToolOnCode(new CTUAction(&Success), "int f(int);")); + EXPECT_TRUE(Success); +} + +TEST(CrossTranslationUnit, IndexFormatCanBeParsed) { + llvm::StringMap<std::string> Index; + Index["a"] = "/b/f1"; + Index["c"] = "/d/f2"; + Index["e"] = "/f/f3"; + std::string IndexText = createCrossTUIndexString(Index); + + int IndexFD; + llvm::SmallString<256> IndexFileName; + ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD, + IndexFileName)); + llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD); + IndexFile.os() << IndexText; + IndexFile.os().flush(); + EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName)); + llvm::Expected<llvm::StringMap<std::string>> IndexOrErr = + parseCrossTUIndex(IndexFileName, ""); + EXPECT_TRUE((bool)IndexOrErr); + llvm::StringMap<std::string> ParsedIndex = IndexOrErr.get(); + for (const auto &E : Index) { + EXPECT_TRUE(ParsedIndex.count(E.getKey())); + EXPECT_EQ(ParsedIndex[E.getKey()], E.getValue()); + } + for (const auto &E : ParsedIndex) + EXPECT_TRUE(Index.count(E.getKey())); +} + +TEST(CrossTranslationUnit, CTUDirIsHandledCorrectly) { + llvm::StringMap<std::string> Index; + Index["a"] = "/b/c/d"; + std::string IndexText = createCrossTUIndexString(Index); + + int IndexFD; + llvm::SmallString<256> IndexFileName; + ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD, + IndexFileName)); + llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD); + IndexFile.os() << IndexText; + IndexFile.os().flush(); + EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName)); + llvm::Expected<llvm::StringMap<std::string>> IndexOrErr = + parseCrossTUIndex(IndexFileName, "/ctudir"); + EXPECT_TRUE((bool)IndexOrErr); + llvm::StringMap<std::string> ParsedIndex = IndexOrErr.get(); + EXPECT_EQ(ParsedIndex["a"], "/ctudir/b/c/d"); +} + +} // end namespace cross_tu +} // end namespace clang |