Mercurial > hg > CbC > CbC_llvm
view clang/unittests/CrossTU/CrossTranslationUnitTest.cpp @ 150:1d019706d866
LLVM10
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 15:10:13 +0900 |
parents | |
children | 2e18cbf3894f |
line wrap: on
line source
//===- unittest/Tooling/CrossTranslationUnitTest.cpp - Tooling unit tests -===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "clang/CrossTU/CrossTranslationUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/AST/ASTConsumer.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Tooling/Tooling.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) { auto FindFInTU = [](const TranslationUnitDecl *TU) { const FunctionDecl *FD = nullptr; for (const Decl *D : TU->decls()) { FD = dyn_cast<FunctionDecl>(D); if (FD && FD->getName() == "f") break; } return FD; }; const TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl(); const FunctionDecl *FD = FindFInTU(TU); 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 = handleExpected( CTU.getCrossTUDefinition(FD, "", IndexFileName, false), []() { return nullptr; }, [](IndexError &) {}); if (NewFDorError) { const FunctionDecl *NewFD = *NewFDorError; *Success = NewFD && NewFD->hasBody() && !OrigFDHasBody; if (NewFD) { // Check GetImportedFromSourceLocation. llvm::Optional<std::pair<SourceLocation, ASTUnit *>> SLocResult = CTU.getImportedFromSourceLocation(NewFD->getLocation()); EXPECT_TRUE(SLocResult); if (SLocResult) { SourceLocation OrigSLoc = (*SLocResult).first; ASTUnit *OrigUnit = (*SLocResult).second; // OrigUnit is created internally by CTU (is not the // ASTWithDefinition). TranslationUnitDecl *OrigTU = OrigUnit->getASTContext().getTranslationUnitDecl(); const FunctionDecl *FDWithDefinition = FindFInTU(OrigTU); EXPECT_TRUE(FDWithDefinition); if (FDWithDefinition) { EXPECT_EQ(FDWithDefinition->getName(), "f"); EXPECT_TRUE(FDWithDefinition->isThisDeclarationADefinition()); EXPECT_EQ(OrigSLoc, FDWithDefinition->getLocation()); } } } } } private: CrossTranslationUnitContext CTU; bool *Success; }; class CTUAction : public clang::ASTFrontendAction { public: CTUAction(bool *Success, unsigned OverrideLimit) : Success(Success), OverrideLimit(OverrideLimit) {} protected: std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance &CI, StringRef) override { CI.getAnalyzerOpts()->CTUImportThreshold = OverrideLimit; return std::make_unique<CTUASTConsumer>(CI, Success); } private: bool *Success; const unsigned OverrideLimit; }; } // end namespace TEST(CrossTranslationUnit, CanLoadFunctionDefinition) { bool Success = false; EXPECT_TRUE(tooling::runToolOnCode(std::make_unique<CTUAction>(&Success, 1u), "int f(int);")); EXPECT_TRUE(Success); } TEST(CrossTranslationUnit, RespectsLoadThreshold) { bool Success = false; EXPECT_TRUE(tooling::runToolOnCode(std::make_unique<CTUAction>(&Success, 0u), "int f(int);")); EXPECT_FALSE(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