brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.0 KiB · bf9e4e1 Raw
224 lines · cpp
1//===- unittests/Frontend/ASTUnitTest.cpp - ASTUnit tests -----------------===//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 <fstream>10 11#include "clang/Basic/FileManager.h"12#include "clang/Driver/CreateASTUnitFromArgs.h"13#include "clang/Driver/CreateInvocationFromArgs.h"14#include "clang/Frontend/ASTUnit.h"15#include "clang/Frontend/CompilerInstance.h"16#include "clang/Frontend/CompilerInvocation.h"17#include "clang/Frontend/PCHContainerOperations.h"18#include "clang/Lex/HeaderSearch.h"19#include "llvm/Support/FileSystem.h"20#include "llvm/Support/Path.h"21#include "llvm/Support/ToolOutputFile.h"22#include "llvm/Support/VirtualFileSystem.h"23#include "gtest/gtest.h"24 25using namespace llvm;26using namespace clang;27 28namespace {29 30class ASTUnitTest : public ::testing::Test {31protected:32  int FD;33  llvm::SmallString<256> InputFileName;34  std::unique_ptr<ToolOutputFile> input_file;35  std::shared_ptr<DiagnosticOptions> DiagOpts =36      std::make_shared<DiagnosticOptions>();37  IntrusiveRefCntPtr<DiagnosticsEngine> Diags;38  std::shared_ptr<CompilerInvocation> CInvok;39  std::shared_ptr<PCHContainerOperations> PCHContainerOps;40 41  std::unique_ptr<ASTUnit> createASTUnit(bool isVolatile) {42    EXPECT_FALSE(llvm::sys::fs::createTemporaryFile("ast-unit", "cpp", FD,43                                                    InputFileName));44    input_file = std::make_unique<ToolOutputFile>(InputFileName, FD);45    input_file->os() << "";46 47    const char *Args[] = {"clang", "-xc++", InputFileName.c_str()};48 49    auto VFS = llvm::vfs::getRealFileSystem();50    Diags = CompilerInstance::createDiagnostics(*VFS, *DiagOpts);51 52    CreateInvocationOptions CIOpts;53    CIOpts.Diags = Diags;54    CIOpts.VFS = VFS;55    CInvok = createInvocation(Args, std::move(CIOpts));56 57    if (!CInvok)58      return nullptr;59 60    auto FileMgr =61        llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions(), VFS);62    PCHContainerOps = std::make_shared<PCHContainerOperations>();63 64    return ASTUnit::LoadFromCompilerInvocation(65        CInvok, PCHContainerOps, DiagOpts, Diags, FileMgr, false,66        CaptureDiagsKind::None, 0, TU_Complete, false, false, isVolatile);67  }68};69 70TEST_F(ASTUnitTest, SaveLoadPreservesLangOptionsInPrintingPolicy) {71  // Check that the printing policy is restored with the correct language72  // options when loading an ASTUnit from a file.  To this end, an ASTUnit73  // for a C++ translation unit is set up and written to a temporary file.74 75  // By default `UseVoidForZeroParams` is true for non-C++ language options,76  // thus we can check this field after loading the ASTUnit to deduce whether77  // the correct (C++) language options were used when setting up the printing78  // policy.79 80  {81    PrintingPolicy PolicyWithDefaultLangOpt(LangOptions{});82    EXPECT_TRUE(PolicyWithDefaultLangOpt.UseVoidForZeroParams);83  }84 85  std::unique_ptr<ASTUnit> AST = createASTUnit(false);86 87  if (!AST)88    FAIL() << "failed to create ASTUnit";89 90  EXPECT_FALSE(AST->getASTContext().getPrintingPolicy().UseVoidForZeroParams);91 92  llvm::SmallString<256> ASTFileName;93  ASSERT_FALSE(94      llvm::sys::fs::createTemporaryFile("ast-unit", "ast", FD, ASTFileName));95  ToolOutputFile ast_file(ASTFileName, FD);96  AST->Save(ASTFileName.str());97 98  EXPECT_TRUE(llvm::sys::fs::exists(ASTFileName));99  HeaderSearchOptions HSOpts;100 101  std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(102      ASTFileName, PCHContainerOps->getRawReader(), ASTUnit::LoadEverything,103      llvm::vfs::getRealFileSystem(), DiagOpts, Diags, FileSystemOptions(),104      HSOpts);105 106  if (!AU)107    FAIL() << "failed to load ASTUnit";108 109  EXPECT_FALSE(AU->getASTContext().getPrintingPolicy().UseVoidForZeroParams);110}111 112TEST_F(ASTUnitTest, GetBufferForFileMemoryMapping) {113  std::unique_ptr<ASTUnit> AST = createASTUnit(true);114 115  if (!AST)116    FAIL() << "failed to create ASTUnit";117 118  std::unique_ptr<llvm::MemoryBuffer> memoryBuffer =119      AST->getBufferForFile(InputFileName);120 121  EXPECT_NE(memoryBuffer->getBufferKind(),122            llvm::MemoryBuffer::MemoryBuffer_MMap);123}124 125TEST_F(ASTUnitTest, ModuleTextualHeader) {126  auto InMemoryFs = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();127  InMemoryFs->addFile("test.cpp", 0, llvm::MemoryBuffer::getMemBuffer(R"cpp(128      #include "Textual.h"129      void foo() {}130    )cpp"));131  InMemoryFs->addFile("m.modulemap", 0, llvm::MemoryBuffer::getMemBuffer(R"cpp(132      module M {133        module Textual {134          textual header "Textual.h"135        }136      }137    )cpp"));138  InMemoryFs->addFile("Textual.h", 0, llvm::MemoryBuffer::getMemBuffer(R"cpp(139      void foo();140    )cpp"));141 142  const char *Args[] = {"clang", "test.cpp", "-fmodule-map-file=m.modulemap",143                        "-fmodule-name=M"};144  Diags = CompilerInstance::createDiagnostics(*InMemoryFs, *DiagOpts);145  CreateInvocationOptions CIOpts;146  CIOpts.Diags = Diags;147  CInvok = createInvocation(Args, std::move(CIOpts));148  ASSERT_TRUE(CInvok);149 150  auto FileMgr =151      llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions(), InMemoryFs);152  PCHContainerOps = std::make_shared<PCHContainerOperations>();153 154  auto AU = ASTUnit::LoadFromCompilerInvocation(155      CInvok, PCHContainerOps, DiagOpts, Diags, FileMgr, false,156      CaptureDiagsKind::None, 1, TU_Complete, false, false, false);157  ASSERT_TRUE(AU);158  auto File = AU->getFileManager().getFileRef("Textual.h", false, false);159  ASSERT_TRUE(bool(File));160  // Verify that we do not crash here.161  EXPECT_TRUE(162      AU->getPreprocessor().getHeaderSearchInfo().getExistingFileInfo(*File));163}164 165TEST_F(ASTUnitTest, LoadFromCommandLineEarlyError) {166  EXPECT_FALSE(167      llvm::sys::fs::createTemporaryFile("ast-unit", "c", FD, InputFileName));168  input_file = std::make_unique<ToolOutputFile>(InputFileName, FD);169  input_file->os() << "";170 171  const char *Args[] = {"clang", "-target", "foobar", InputFileName.c_str()};172 173  auto Diags = CompilerInstance::createDiagnostics(174      *llvm::vfs::getRealFileSystem(), *DiagOpts);175  auto PCHContainerOps = std::make_shared<PCHContainerOperations>();176  std::unique_ptr<clang::ASTUnit> ErrUnit;177 178  std::unique_ptr<ASTUnit> AST = CreateASTUnitFromCommandLine(179      &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "",180      false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false,181      false, SkipFunctionBodiesScope::None, false, true, false, false,182      std::nullopt, &ErrUnit, nullptr);183 184  ASSERT_EQ(AST, nullptr);185  ASSERT_NE(ErrUnit, nullptr);186  ASSERT_TRUE(Diags->hasErrorOccurred());187  ASSERT_NE(ErrUnit->stored_diag_size(), 0U);188}189 190TEST_F(ASTUnitTest, LoadFromCommandLineWorkingDirectory) {191  EXPECT_FALSE(192      llvm::sys::fs::createTemporaryFile("bar", "c", FD, InputFileName));193  auto Input = std::make_unique<ToolOutputFile>(InputFileName, FD);194  Input->os() << "";195 196  SmallString<128> WorkingDir;197  ASSERT_FALSE(sys::fs::createUniqueDirectory("foo", WorkingDir));198  const char *Args[] = {"clang", "-working-directory", WorkingDir.c_str(),199                        InputFileName.c_str()};200 201  auto Diags = CompilerInstance::createDiagnostics(202      *llvm::vfs::getRealFileSystem(), *DiagOpts);203  auto PCHContainerOps = std::make_shared<PCHContainerOperations>();204  std::unique_ptr<clang::ASTUnit> ErrUnit;205 206  std::unique_ptr<ASTUnit> AST = CreateASTUnitFromCommandLine(207      &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "",208      false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false,209      false, SkipFunctionBodiesScope::None, false, true, false, false,210      std::nullopt, &ErrUnit, nullptr);211 212  ASSERT_NE(AST, nullptr);213  ASSERT_FALSE(Diags->hasErrorOccurred());214 215  // Make sure '-working-directory' sets both the FileSystemOpts and underlying216  // VFS working directory.217  const auto &FM = AST->getFileManager();218  const auto &VFS = FM.getVirtualFileSystem();219  ASSERT_EQ(*VFS.getCurrentWorkingDirectory(), WorkingDir.str());220  ASSERT_EQ(FM.getFileSystemOpts().WorkingDir, WorkingDir.str());221}222 223} // anonymous namespace224