aboutsummaryrefslogtreecommitdiff
path: root/unittests/CrossTU/CrossTranslationUnitTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/CrossTU/CrossTranslationUnitTest.cpp')
-rw-r--r--unittests/CrossTU/CrossTranslationUnitTest.cpp158
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