diff options
author | 2020-08-03 14:31:31 +0000 | |
---|---|---|
committer | 2020-08-03 14:31:31 +0000 | |
commit | e5dd70708596ae51455a0ffa086a00c5b29f8583 (patch) | |
tree | 5d676f27b570bacf71e786c3b5cff3e6f6679b59 /gnu/llvm/clang/unittests/Frontend | |
parent | Import LLVM 10.0.0 release including clang, lld and lldb. (diff) | |
download | wireguard-openbsd-e5dd70708596ae51455a0ffa086a00c5b29f8583.tar.xz wireguard-openbsd-e5dd70708596ae51455a0ffa086a00c5b29f8583.zip |
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom
tested by plenty
Diffstat (limited to 'gnu/llvm/clang/unittests/Frontend')
9 files changed, 1100 insertions, 0 deletions
diff --git a/gnu/llvm/clang/unittests/Frontend/ASTUnitTest.cpp b/gnu/llvm/clang/unittests/Frontend/ASTUnitTest.cpp new file mode 100644 index 00000000000..5cb20872f0b --- /dev/null +++ b/gnu/llvm/clang/unittests/Frontend/ASTUnitTest.cpp @@ -0,0 +1,113 @@ +//===- unittests/Frontend/ASTUnitTest.cpp - ASTUnit 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 <fstream> + +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/PCHContainerOperations.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/ToolOutputFile.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { + +class ASTUnitTest : public ::testing::Test { +protected: + int FD; + llvm::SmallString<256> InputFileName; + std::unique_ptr<ToolOutputFile> input_file; + IntrusiveRefCntPtr<DiagnosticsEngine> Diags; + std::shared_ptr<CompilerInvocation> CInvok; + std::shared_ptr<PCHContainerOperations> PCHContainerOps; + + std::unique_ptr<ASTUnit> createASTUnit(bool isVolatile) { + EXPECT_FALSE(llvm::sys::fs::createTemporaryFile("ast-unit", "cpp", FD, + InputFileName)); + input_file = std::make_unique<ToolOutputFile>(InputFileName, FD); + input_file->os() << ""; + + const char *Args[] = {"clang", "-xc++", InputFileName.c_str()}; + + Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions()); + + CInvok = createInvocationFromCommandLine(Args, Diags); + + if (!CInvok) + return nullptr; + + FileManager *FileMgr = + new FileManager(FileSystemOptions(), vfs::getRealFileSystem()); + PCHContainerOps = std::make_shared<PCHContainerOperations>(); + + return ASTUnit::LoadFromCompilerInvocation( + CInvok, PCHContainerOps, Diags, FileMgr, false, CaptureDiagsKind::None, + 0, TU_Complete, false, false, isVolatile); + } +}; + +TEST_F(ASTUnitTest, SaveLoadPreservesLangOptionsInPrintingPolicy) { + // Check that the printing policy is restored with the correct language + // options when loading an ASTUnit from a file. To this end, an ASTUnit + // for a C++ translation unit is set up and written to a temporary file. + + // By default `UseVoidForZeroParams` is true for non-C++ language options, + // thus we can check this field after loading the ASTUnit to deduce whether + // the correct (C++) language options were used when setting up the printing + // policy. + + { + PrintingPolicy PolicyWithDefaultLangOpt(LangOptions{}); + EXPECT_TRUE(PolicyWithDefaultLangOpt.UseVoidForZeroParams); + } + + std::unique_ptr<ASTUnit> AST = createASTUnit(false); + + if (!AST) + FAIL() << "failed to create ASTUnit"; + + EXPECT_FALSE(AST->getASTContext().getPrintingPolicy().UseVoidForZeroParams); + + llvm::SmallString<256> ASTFileName; + ASSERT_FALSE( + llvm::sys::fs::createTemporaryFile("ast-unit", "ast", FD, ASTFileName)); + ToolOutputFile ast_file(ASTFileName, FD); + AST->Save(ASTFileName.str()); + + EXPECT_TRUE(llvm::sys::fs::exists(ASTFileName)); + + std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile( + ASTFileName.str(), PCHContainerOps->getRawReader(), + ASTUnit::LoadEverything, Diags, FileSystemOptions(), + /*UseDebugInfo=*/false); + + if (!AU) + FAIL() << "failed to load ASTUnit"; + + EXPECT_FALSE(AU->getASTContext().getPrintingPolicy().UseVoidForZeroParams); +} + +TEST_F(ASTUnitTest, GetBufferForFileMemoryMapping) { + std::unique_ptr<ASTUnit> AST = createASTUnit(true); + + if (!AST) + FAIL() << "failed to create ASTUnit"; + + std::unique_ptr<llvm::MemoryBuffer> memoryBuffer = + AST->getBufferForFile(InputFileName); + + EXPECT_NE(memoryBuffer->getBufferKind(), + llvm::MemoryBuffer::MemoryBuffer_MMap); +} + +} // anonymous namespace diff --git a/gnu/llvm/clang/unittests/Frontend/CMakeLists.txt b/gnu/llvm/clang/unittests/Frontend/CMakeLists.txt new file mode 100644 index 00000000000..cde19e91061 --- /dev/null +++ b/gnu/llvm/clang/unittests/Frontend/CMakeLists.txt @@ -0,0 +1,25 @@ +set(LLVM_LINK_COMPONENTS + Support + ) + +add_clang_unittest(FrontendTests + ASTUnitTest.cpp + CompilerInstanceTest.cpp + FixedPointString.cpp + FrontendActionTest.cpp + CodeGenActionTest.cpp + ParsedSourceLocationTest.cpp + PCHPreambleTest.cpp + OutputStreamTest.cpp + ) +clang_target_link_libraries(FrontendTests + PRIVATE + clangAST + clangBasic + clangFrontend + clangLex + clangSema + clangCodeGen + clangFrontendTool + clangSerialization + ) diff --git a/gnu/llvm/clang/unittests/Frontend/CodeGenActionTest.cpp b/gnu/llvm/clang/unittests/Frontend/CodeGenActionTest.cpp new file mode 100644 index 00000000000..455ec705f88 --- /dev/null +++ b/gnu/llvm/clang/unittests/Frontend/CodeGenActionTest.cpp @@ -0,0 +1,62 @@ +//===- unittests/Frontend/CodeGenActionTest.cpp --- FrontendAction 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 +// +//===----------------------------------------------------------------------===// +// +// Unit tests for CodeGenAction. +// +//===----------------------------------------------------------------------===// + +#include "clang/CodeGen/CodeGenAction.h" +#include "clang/Basic/LangStandard.h" +#include "clang/CodeGen/BackendUtil.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; +using namespace clang::frontend; + +namespace { + + +class NullCodeGenAction : public CodeGenAction { +public: + NullCodeGenAction(llvm::LLVMContext *_VMContext = nullptr) + : CodeGenAction(Backend_EmitMCNull, _VMContext) {} + + // The action does not call methods of ATContext. + void ExecuteAction() override { + CompilerInstance &CI = getCompilerInstance(); + if (!CI.hasPreprocessor()) + return; + if (!CI.hasSema()) + CI.createSema(getTranslationUnitKind(), nullptr); + } +}; + + +TEST(CodeGenTest, TestNullCodeGen) { + auto Invocation = std::make_shared<CompilerInvocation>(); + Invocation->getPreprocessorOpts().addRemappedFile( + "test.cc", + MemoryBuffer::getMemBuffer("").release()); + Invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.cc", Language::CXX)); + Invocation->getFrontendOpts().ProgramAction = EmitLLVM; + Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + CompilerInstance Compiler; + Compiler.setInvocation(std::move(Invocation)); + Compiler.createDiagnostics(); + EXPECT_TRUE(Compiler.hasDiagnostics()); + + std::unique_ptr<FrontendAction> Act(new NullCodeGenAction); + bool Success = Compiler.ExecuteAction(*Act); + EXPECT_TRUE(Success); +} + +} diff --git a/gnu/llvm/clang/unittests/Frontend/CompilerInstanceTest.cpp b/gnu/llvm/clang/unittests/Frontend/CompilerInstanceTest.cpp new file mode 100644 index 00000000000..d2377d07406 --- /dev/null +++ b/gnu/llvm/clang/unittests/Frontend/CompilerInstanceTest.cpp @@ -0,0 +1,94 @@ +//===- unittests/Frontend/CompilerInstanceTest.cpp - CI 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/Frontend/CompilerInstance.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/ToolOutputFile.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { + +TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) { + // Create a temporary VFS overlay yaml file. + int FD; + SmallString<256> FileName; + ASSERT_FALSE(sys::fs::createTemporaryFile("vfs", "yaml", FD, FileName)); + ToolOutputFile File(FileName, FD); + + SmallString<256> CurrentPath; + sys::fs::current_path(CurrentPath); + sys::fs::make_absolute(CurrentPath, FileName); + + // Mount the VFS file itself on the path 'virtual.file'. Makes this test + // a bit shorter than creating a new dummy file just for this purpose. + const std::string CurrentPathStr = CurrentPath.str(); + const std::string FileNameStr = FileName.str(); + const char *VFSYaml = "{ 'version': 0, 'roots': [\n" + " { 'name': '%s',\n" + " 'type': 'directory',\n" + " 'contents': [\n" + " { 'name': 'vfs-virtual.file', 'type': 'file',\n" + " 'external-contents': '%s'\n" + " }\n" + " ]\n" + " }\n" + "]}\n"; + File.os() << format(VFSYaml, CurrentPathStr.c_str(), FileName.c_str()); + File.os().flush(); + + // Create a CompilerInvocation that uses this overlay file. + const std::string VFSArg = "-ivfsoverlay" + FileNameStr; + const char *Args[] = {"clang", VFSArg.c_str(), "-xc++", "-"}; + + IntrusiveRefCntPtr<DiagnosticsEngine> Diags = + CompilerInstance::createDiagnostics(new DiagnosticOptions()); + + std::shared_ptr<CompilerInvocation> CInvok = + createInvocationFromCommandLine(Args, Diags); + + if (!CInvok) + FAIL() << "could not create compiler invocation"; + // Create a minimal CompilerInstance which should use the VFS we specified + // in the CompilerInvocation (as we don't explicitly set our own). + CompilerInstance Instance; + Instance.setDiagnostics(Diags.get()); + Instance.setInvocation(CInvok); + Instance.createFileManager(); + + // Check if the virtual file exists which means that our VFS is used by the + // CompilerInstance. + ASSERT_TRUE(Instance.getFileManager().getFile("vfs-virtual.file")); +} + +TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) { + auto DiagOpts = new DiagnosticOptions(); + // Tell the diagnostics engine to emit the diagnostic log to STDERR. This + // ensures that a chained diagnostic consumer is created so that the test can + // exercise the unowned diagnostic consumer in a chained consumer. + DiagOpts->DiagnosticLogFile = "-"; + + // Create the diagnostic engine with unowned consumer. + std::string DiagnosticOutput; + llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); + auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>( + DiagnosticsOS, new DiagnosticOptions()); + CompilerInstance Instance; + IntrusiveRefCntPtr<DiagnosticsEngine> Diags = Instance.createDiagnostics( + DiagOpts, DiagPrinter.get(), /*ShouldOwnClient=*/false); + + Diags->Report(diag::err_expected) << "no crash"; + ASSERT_EQ(DiagnosticsOS.str(), "error: expected no crash\n"); +} + +} // anonymous namespace diff --git a/gnu/llvm/clang/unittests/Frontend/FixedPointString.cpp b/gnu/llvm/clang/unittests/Frontend/FixedPointString.cpp new file mode 100644 index 00000000000..755efd7fcaa --- /dev/null +++ b/gnu/llvm/clang/unittests/Frontend/FixedPointString.cpp @@ -0,0 +1,107 @@ +#include "clang/AST/Type.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/SmallString.h" +#include "gtest/gtest.h" + +using clang::FixedPointValueToString; +using llvm::APSInt; +using llvm::SmallString; + +namespace { + +TEST(FixedPointString, DifferentTypes) { + SmallString<64> S; + FixedPointValueToString(S, APSInt::get(320), 7); + ASSERT_STREQ(S.c_str(), "2.5"); + + S.clear(); + FixedPointValueToString(S, APSInt::get(0), 7); + ASSERT_STREQ(S.c_str(), "0.0"); + + // signed short _Accum + S.clear(); + FixedPointValueToString(S, APSInt::getMaxValue(16, /*Unsigned=*/false), 7); + ASSERT_STREQ(S.c_str(), "255.9921875"); + + // signed _Accum + S.clear(); + FixedPointValueToString(S, APSInt::getMaxValue(32, /*Unsigned=*/false), 15); + ASSERT_STREQ(S.c_str(), "65535.999969482421875"); + + // signed long _Accum + S.clear(); + FixedPointValueToString(S, APSInt::getMaxValue(64, /*Unsigned=*/false), 31); + ASSERT_STREQ(S.c_str(), "4294967295.9999999995343387126922607421875"); + + // unsigned short _Accum + S.clear(); + FixedPointValueToString(S, APSInt::getMaxValue(16, /*Unsigned=*/true), 8); + ASSERT_STREQ(S.c_str(), "255.99609375"); + + // unsigned _Accum + S.clear(); + FixedPointValueToString(S, APSInt::getMaxValue(32, /*Unsigned=*/true), 16); + ASSERT_STREQ(S.c_str(), "65535.9999847412109375"); + + // unsigned long _Accum + S.clear(); + FixedPointValueToString(S, APSInt::getMaxValue(64, /*Unsigned=*/true), 32); + ASSERT_STREQ(S.c_str(), "4294967295.99999999976716935634613037109375"); + + // signed short _Fract + S.clear(); + FixedPointValueToString(S, APSInt::getMaxValue(8, /*Unsigned=*/false), 7); + ASSERT_STREQ(S.c_str(), "0.9921875"); + + // signed _Fract + S.clear(); + FixedPointValueToString(S, APSInt::getMaxValue(16, /*Unsigned=*/false), 15); + ASSERT_STREQ(S.c_str(), "0.999969482421875"); + + // signed long _Fract + S.clear(); + FixedPointValueToString(S, APSInt::getMaxValue(32, /*Unsigned=*/false), 31); + ASSERT_STREQ(S.c_str(), "0.9999999995343387126922607421875"); + + // unsigned short _Fract + S.clear(); + FixedPointValueToString(S, APSInt::getMaxValue(8, /*Unsigned=*/true), 8); + ASSERT_STREQ(S.c_str(), "0.99609375"); + + // unsigned _Fract + S.clear(); + FixedPointValueToString(S, APSInt::getMaxValue(16, /*Unsigned=*/true), 16); + ASSERT_STREQ(S.c_str(), "0.9999847412109375"); + + // unsigned long _Fract + S.clear(); + FixedPointValueToString(S, APSInt::getMaxValue(32, /*Unsigned=*/true), 32); + ASSERT_STREQ(S.c_str(), "0.99999999976716935634613037109375"); +} + +TEST(FixedPointString, Negative) { + SmallString<64> S; + FixedPointValueToString(S, APSInt::get(-320), 7); + ASSERT_STREQ(S.c_str(), "-2.5"); + + S.clear(); + FixedPointValueToString(S, APSInt::get(-64), 7); + ASSERT_STREQ(S.c_str(), "-0.5"); + + // signed short _Accum + S.clear(); + FixedPointValueToString(S, APSInt::getMinValue(16, /*Unsigned=*/false), 7); + ASSERT_STREQ(S.c_str(), "-256.0"); + + // signed _Accum + S.clear(); + FixedPointValueToString(S, APSInt::getMinValue(32, /*Unsigned=*/false), 15); + ASSERT_STREQ(S.c_str(), "-65536.0"); + + // signed long _Accum + S.clear(); + FixedPointValueToString(S, APSInt::getMinValue(64, /*Unsigned=*/false), 31); + ASSERT_STREQ(S.c_str(), "-4294967296.0"); +} + +} // namespace diff --git a/gnu/llvm/clang/unittests/Frontend/FrontendActionTest.cpp b/gnu/llvm/clang/unittests/Frontend/FrontendActionTest.cpp new file mode 100644 index 00000000000..95be040ddf1 --- /dev/null +++ b/gnu/llvm/clang/unittests/Frontend/FrontendActionTest.cpp @@ -0,0 +1,295 @@ +//===- unittests/Frontend/FrontendActionTest.cpp - FrontendAction 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/Frontend/FrontendAction.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/LangStandard.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "clang/Sema/Sema.h" +#include "clang/Serialization/InMemoryModuleCache.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/ToolOutputFile.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { + +class TestASTFrontendAction : public ASTFrontendAction { +public: + TestASTFrontendAction(bool enableIncrementalProcessing = false, + bool actOnEndOfTranslationUnit = false) + : EnableIncrementalProcessing(enableIncrementalProcessing), + ActOnEndOfTranslationUnit(actOnEndOfTranslationUnit) { } + + bool EnableIncrementalProcessing; + bool ActOnEndOfTranslationUnit; + std::vector<std::string> decl_names; + + bool BeginSourceFileAction(CompilerInstance &ci) override { + if (EnableIncrementalProcessing) + ci.getPreprocessor().enableIncrementalProcessing(); + + return ASTFrontendAction::BeginSourceFileAction(ci); + } + + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override { + return std::make_unique<Visitor>(CI, ActOnEndOfTranslationUnit, + decl_names); + } + +private: + class Visitor : public ASTConsumer, public RecursiveASTVisitor<Visitor> { + public: + Visitor(CompilerInstance &CI, bool ActOnEndOfTranslationUnit, + std::vector<std::string> &decl_names) : + CI(CI), ActOnEndOfTranslationUnit(ActOnEndOfTranslationUnit), + decl_names_(decl_names) {} + + void HandleTranslationUnit(ASTContext &context) override { + if (ActOnEndOfTranslationUnit) { + CI.getSema().ActOnEndOfTranslationUnit(); + } + TraverseDecl(context.getTranslationUnitDecl()); + } + + virtual bool VisitNamedDecl(NamedDecl *Decl) { + decl_names_.push_back(Decl->getQualifiedNameAsString()); + return true; + } + + private: + CompilerInstance &CI; + bool ActOnEndOfTranslationUnit; + std::vector<std::string> &decl_names_; + }; +}; + +TEST(ASTFrontendAction, Sanity) { + auto invocation = std::make_shared<CompilerInvocation>(); + invocation->getPreprocessorOpts().addRemappedFile( + "test.cc", + MemoryBuffer::getMemBuffer("int main() { float x; }").release()); + invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.cc", Language::CXX)); + invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; + invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + CompilerInstance compiler; + compiler.setInvocation(std::move(invocation)); + compiler.createDiagnostics(); + + TestASTFrontendAction test_action; + ASSERT_TRUE(compiler.ExecuteAction(test_action)); + ASSERT_EQ(2U, test_action.decl_names.size()); + EXPECT_EQ("main", test_action.decl_names[0]); + EXPECT_EQ("x", test_action.decl_names[1]); +} + +TEST(ASTFrontendAction, IncrementalParsing) { + auto invocation = std::make_shared<CompilerInvocation>(); + invocation->getPreprocessorOpts().addRemappedFile( + "test.cc", + MemoryBuffer::getMemBuffer("int main() { float x; }").release()); + invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.cc", Language::CXX)); + invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; + invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + CompilerInstance compiler; + compiler.setInvocation(std::move(invocation)); + compiler.createDiagnostics(); + + TestASTFrontendAction test_action(/*enableIncrementalProcessing=*/true); + ASSERT_TRUE(compiler.ExecuteAction(test_action)); + ASSERT_EQ(2U, test_action.decl_names.size()); + EXPECT_EQ("main", test_action.decl_names[0]); + EXPECT_EQ("x", test_action.decl_names[1]); +} + +TEST(ASTFrontendAction, LateTemplateIncrementalParsing) { + auto invocation = std::make_shared<CompilerInvocation>(); + invocation->getLangOpts()->CPlusPlus = true; + invocation->getLangOpts()->DelayedTemplateParsing = true; + invocation->getPreprocessorOpts().addRemappedFile( + "test.cc", MemoryBuffer::getMemBuffer( + "template<typename T> struct A { A(T); T data; };\n" + "template<typename T> struct B: public A<T> {\n" + " B();\n" + " B(B const& b): A<T>(b.data) {}\n" + "};\n" + "B<char> c() { return B<char>(); }\n").release()); + invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.cc", Language::CXX)); + invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; + invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + CompilerInstance compiler; + compiler.setInvocation(std::move(invocation)); + compiler.createDiagnostics(); + + TestASTFrontendAction test_action(/*enableIncrementalProcessing=*/true, + /*actOnEndOfTranslationUnit=*/true); + ASSERT_TRUE(compiler.ExecuteAction(test_action)); + ASSERT_EQ(13U, test_action.decl_names.size()); + EXPECT_EQ("A", test_action.decl_names[0]); + EXPECT_EQ("c", test_action.decl_names[12]); +} + +struct TestPPCallbacks : public PPCallbacks { + TestPPCallbacks() : SeenEnd(false) {} + + void EndOfMainFile() override { SeenEnd = true; } + + bool SeenEnd; +}; + +class TestPPCallbacksFrontendAction : public PreprocessorFrontendAction { + TestPPCallbacks *Callbacks; + +public: + TestPPCallbacksFrontendAction(TestPPCallbacks *C) + : Callbacks(C), SeenEnd(false) {} + + void ExecuteAction() override { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + PP.addPPCallbacks(std::unique_ptr<TestPPCallbacks>(Callbacks)); + PP.EnterMainSourceFile(); + } + void EndSourceFileAction() override { SeenEnd = Callbacks->SeenEnd; } + + bool SeenEnd; +}; + +TEST(PreprocessorFrontendAction, EndSourceFile) { + auto Invocation = std::make_shared<CompilerInvocation>(); + Invocation->getPreprocessorOpts().addRemappedFile( + "test.cc", + MemoryBuffer::getMemBuffer("int main() { float x; }").release()); + Invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.cc", Language::CXX)); + Invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; + Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + CompilerInstance Compiler; + Compiler.setInvocation(std::move(Invocation)); + Compiler.createDiagnostics(); + + TestPPCallbacks *Callbacks = new TestPPCallbacks; + TestPPCallbacksFrontendAction TestAction(Callbacks); + ASSERT_FALSE(Callbacks->SeenEnd); + ASSERT_FALSE(TestAction.SeenEnd); + ASSERT_TRUE(Compiler.ExecuteAction(TestAction)); + // Check that EndOfMainFile was called before EndSourceFileAction. + ASSERT_TRUE(TestAction.SeenEnd); +} + +class TypoExternalSemaSource : public ExternalSemaSource { + CompilerInstance &CI; + +public: + TypoExternalSemaSource(CompilerInstance &CI) : CI(CI) {} + + TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, int LookupKind, + Scope *S, CXXScopeSpec *SS, + CorrectionCandidateCallback &CCC, + DeclContext *MemberContext, bool EnteringContext, + const ObjCObjectPointerType *OPT) override { + // Generate a fake typo correction with one attached note. + ASTContext &Ctx = CI.getASTContext(); + TypoCorrection TC(DeclarationName(&Ctx.Idents.get("moo"))); + unsigned DiagID = Ctx.getDiagnostics().getCustomDiagID( + DiagnosticsEngine::Note, "This is a note"); + TC.addExtraDiagnostic(PartialDiagnostic(DiagID, Ctx.getDiagAllocator())); + return TC; + } +}; + +struct TypoDiagnosticConsumer : public DiagnosticConsumer { + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) override { + // Capture errors and notes. There should be one of each. + if (DiagLevel == DiagnosticsEngine::Error) { + assert(Error.empty()); + Info.FormatDiagnostic(Error); + } else { + assert(Note.empty()); + Info.FormatDiagnostic(Note); + } + } + SmallString<32> Error; + SmallString<32> Note; +}; + +TEST(ASTFrontendAction, ExternalSemaSource) { + auto Invocation = std::make_shared<CompilerInvocation>(); + Invocation->getLangOpts()->CPlusPlus = true; + Invocation->getPreprocessorOpts().addRemappedFile( + "test.cc", MemoryBuffer::getMemBuffer("void fooo();\n" + "int main() { foo(); }") + .release()); + Invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.cc", Language::CXX)); + Invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; + Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + CompilerInstance Compiler; + Compiler.setInvocation(std::move(Invocation)); + auto *TDC = new TypoDiagnosticConsumer; + Compiler.createDiagnostics(TDC, /*ShouldOwnClient=*/true); + Compiler.setExternalSemaSource(new TypoExternalSemaSource(Compiler)); + + SyntaxOnlyAction TestAction; + ASSERT_TRUE(Compiler.ExecuteAction(TestAction)); + // There should be one error correcting to 'moo' and a note attached to it. + EXPECT_EQ("use of undeclared identifier 'foo'; did you mean 'moo'?", + TDC->Error.str().str()); + EXPECT_EQ("This is a note", TDC->Note.str().str()); +} + +TEST(GeneratePCHFrontendAction, CacheGeneratedPCH) { + // Create a temporary file for writing out the PCH that will be cleaned up. + int PCHFD; + llvm::SmallString<128> PCHFilename; + ASSERT_FALSE( + llvm::sys::fs::createTemporaryFile("test.h", "pch", PCHFD, PCHFilename)); + llvm::ToolOutputFile PCHFile(PCHFilename, PCHFD); + + for (bool ShouldCache : {false, true}) { + auto Invocation = std::make_shared<CompilerInvocation>(); + Invocation->getLangOpts()->CacheGeneratedPCH = ShouldCache; + Invocation->getPreprocessorOpts().addRemappedFile( + "test.h", + MemoryBuffer::getMemBuffer("int foo(void) { return 1; }\n").release()); + Invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.h", Language::C)); + Invocation->getFrontendOpts().OutputFile = StringRef(PCHFilename); + Invocation->getFrontendOpts().ProgramAction = frontend::GeneratePCH; + Invocation->getTargetOpts().Triple = "x86_64-apple-darwin19.0.0"; + CompilerInstance Compiler; + Compiler.setInvocation(std::move(Invocation)); + Compiler.createDiagnostics(); + + GeneratePCHAction TestAction; + ASSERT_TRUE(Compiler.ExecuteAction(TestAction)); + + // Check whether the PCH was cached. + if (ShouldCache) + EXPECT_EQ(InMemoryModuleCache::Final, + Compiler.getModuleCache().getPCMState(PCHFilename)); + else + EXPECT_EQ(InMemoryModuleCache::Unknown, + Compiler.getModuleCache().getPCMState(PCHFilename)); + } +} + +} // anonymous namespace diff --git a/gnu/llvm/clang/unittests/Frontend/OutputStreamTest.cpp b/gnu/llvm/clang/unittests/Frontend/OutputStreamTest.cpp new file mode 100644 index 00000000000..6a867bf053c --- /dev/null +++ b/gnu/llvm/clang/unittests/Frontend/OutputStreamTest.cpp @@ -0,0 +1,103 @@ +//===- unittests/Frontend/OutputStreamTest.cpp --- FrontendAction 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/Basic/LangStandard.h" +#include "clang/CodeGen/BackendUtil.h" +#include "clang/CodeGen/CodeGenAction.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/FrontendTool/Utils.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; +using namespace clang::frontend; + +namespace { + +TEST(FrontendOutputTests, TestOutputStream) { + auto Invocation = std::make_shared<CompilerInvocation>(); + Invocation->getPreprocessorOpts().addRemappedFile( + "test.cc", MemoryBuffer::getMemBuffer("").release()); + Invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.cc", Language::CXX)); + Invocation->getFrontendOpts().ProgramAction = EmitBC; + Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + CompilerInstance Compiler; + + SmallVector<char, 256> IRBuffer; + std::unique_ptr<raw_pwrite_stream> IRStream( + new raw_svector_ostream(IRBuffer)); + + Compiler.setOutputStream(std::move(IRStream)); + Compiler.setInvocation(std::move(Invocation)); + Compiler.createDiagnostics(); + + bool Success = ExecuteCompilerInvocation(&Compiler); + EXPECT_TRUE(Success); + EXPECT_TRUE(!IRBuffer.empty()); + EXPECT_TRUE(StringRef(IRBuffer.data()).startswith("BC")); +} + +TEST(FrontendOutputTests, TestVerboseOutputStreamShared) { + auto Invocation = std::make_shared<CompilerInvocation>(); + Invocation->getPreprocessorOpts().addRemappedFile( + "test.cc", MemoryBuffer::getMemBuffer("invalid").release()); + Invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.cc", Language::CXX)); + Invocation->getFrontendOpts().ProgramAction = EmitBC; + Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + CompilerInstance Compiler; + + std::string VerboseBuffer; + raw_string_ostream VerboseStream(VerboseBuffer); + + Compiler.setOutputStream(std::make_unique<raw_null_ostream>()); + Compiler.setInvocation(std::move(Invocation)); + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); + Compiler.createDiagnostics( + new TextDiagnosticPrinter(llvm::nulls(), &*DiagOpts), true); + Compiler.setVerboseOutputStream(VerboseStream); + + bool Success = ExecuteCompilerInvocation(&Compiler); + EXPECT_FALSE(Success); + EXPECT_TRUE(!VerboseStream.str().empty()); + EXPECT_TRUE(StringRef(VerboseBuffer.data()).contains("errors generated")); +} + +TEST(FrontendOutputTests, TestVerboseOutputStreamOwned) { + std::string VerboseBuffer; + bool Success; + { + auto Invocation = std::make_shared<CompilerInvocation>(); + Invocation->getPreprocessorOpts().addRemappedFile( + "test.cc", MemoryBuffer::getMemBuffer("invalid").release()); + Invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.cc", Language::CXX)); + Invocation->getFrontendOpts().ProgramAction = EmitBC; + Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + CompilerInstance Compiler; + + std::unique_ptr<raw_ostream> VerboseStream = + std::make_unique<raw_string_ostream>(VerboseBuffer); + + Compiler.setOutputStream(std::make_unique<raw_null_ostream>()); + Compiler.setInvocation(std::move(Invocation)); + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); + Compiler.createDiagnostics( + new TextDiagnosticPrinter(llvm::nulls(), &*DiagOpts), true); + Compiler.setVerboseOutputStream(std::move(VerboseStream)); + + Success = ExecuteCompilerInvocation(&Compiler); + } + EXPECT_FALSE(Success); + EXPECT_TRUE(!VerboseBuffer.empty()); + EXPECT_TRUE(StringRef(VerboseBuffer.data()).contains("errors generated")); +} +} diff --git a/gnu/llvm/clang/unittests/Frontend/PCHPreambleTest.cpp b/gnu/llvm/clang/unittests/Frontend/PCHPreambleTest.cpp new file mode 100644 index 00000000000..6136b095949 --- /dev/null +++ b/gnu/llvm/clang/unittests/Frontend/PCHPreambleTest.cpp @@ -0,0 +1,265 @@ +//====-- unittests/Frontend/PCHPreambleTest.cpp - FrontendAction 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/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/FrontendOptions.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { + +class ReadCountingInMemoryFileSystem : public vfs::InMemoryFileSystem +{ + std::map<std::string, unsigned> ReadCounts; + +public: + ErrorOr<std::unique_ptr<vfs::File>> openFileForRead(const Twine &Path) override + { + SmallVector<char, 128> PathVec; + Path.toVector(PathVec); + llvm::sys::path::remove_dots(PathVec, true); + ++ReadCounts[std::string(PathVec.begin(), PathVec.end())]; + return InMemoryFileSystem::openFileForRead(Path); + } + + unsigned GetReadCount(const Twine &Path) const + { + auto it = ReadCounts.find(Path.str()); + return it == ReadCounts.end() ? 0 : it->second; + } +}; + +class PCHPreambleTest : public ::testing::Test { + IntrusiveRefCntPtr<ReadCountingInMemoryFileSystem> VFS; + StringMap<std::string> RemappedFiles; + std::shared_ptr<PCHContainerOperations> PCHContainerOpts; + FileSystemOptions FSOpts; + +public: + void SetUp() override { ResetVFS(); } + void TearDown() override {} + + void ResetVFS() { + VFS = new ReadCountingInMemoryFileSystem(); + // We need the working directory to be set to something absolute, + // otherwise it ends up being inadvertently set to the current + // working directory in the real file system due to a series of + // unfortunate conditions interacting badly. + // What's more, this path *must* be absolute on all (real) + // filesystems, so just '/' won't work (e.g. on Win32). + VFS->setCurrentWorkingDirectory("//./"); + } + + void AddFile(const std::string &Filename, const std::string &Contents) { + ::time_t now; + ::time(&now); + VFS->addFile(Filename, now, MemoryBuffer::getMemBufferCopy(Contents, Filename)); + } + + void RemapFile(const std::string &Filename, const std::string &Contents) { + RemappedFiles[Filename] = Contents; + } + + std::unique_ptr<ASTUnit> ParseAST(const std::string &EntryFile) { + PCHContainerOpts = std::make_shared<PCHContainerOperations>(); + std::shared_ptr<CompilerInvocation> CI(new CompilerInvocation); + CI->getFrontendOpts().Inputs.push_back( + FrontendInputFile(EntryFile, FrontendOptions::getInputKindForExtension( + llvm::sys::path::extension(EntryFile).substr(1)))); + + CI->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + + CI->getPreprocessorOpts().RemappedFileBuffers = GetRemappedFiles(); + + PreprocessorOptions &PPOpts = CI->getPreprocessorOpts(); + PPOpts.RemappedFilesKeepOriginalName = true; + + IntrusiveRefCntPtr<DiagnosticsEngine> + Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions, new DiagnosticConsumer)); + + FileManager *FileMgr = new FileManager(FSOpts, VFS); + + std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation( + CI, PCHContainerOpts, Diags, FileMgr, false, CaptureDiagsKind::None, + /*PrecompilePreambleAfterNParses=*/1); + return AST; + } + + bool ReparseAST(const std::unique_ptr<ASTUnit> &AST) { + bool reparseFailed = AST->Reparse(PCHContainerOpts, GetRemappedFiles(), VFS); + return !reparseFailed; + } + + unsigned GetFileReadCount(const std::string &Filename) const { + return VFS->GetReadCount(Filename); + } + +private: + std::vector<std::pair<std::string, llvm::MemoryBuffer *>> + GetRemappedFiles() const { + std::vector<std::pair<std::string, llvm::MemoryBuffer *>> Remapped; + for (const auto &RemappedFile : RemappedFiles) { + std::unique_ptr<MemoryBuffer> buf = MemoryBuffer::getMemBufferCopy( + RemappedFile.second, RemappedFile.first()); + Remapped.emplace_back(RemappedFile.first(), buf.release()); + } + return Remapped; + } +}; + +TEST_F(PCHPreambleTest, ReparseReusesPreambleWithUnsavedFileNotExistingOnDisk) { + std::string Header1 = "//./header1.h"; + std::string MainName = "//./main.cpp"; + AddFile(MainName, R"cpp( +#include "//./header1.h" +int main() { return ZERO; } +)cpp"); + RemapFile(Header1, "#define ZERO 0\n"); + + // Parse with header file provided as unsaved file, which does not exist on + // disk. + std::unique_ptr<ASTUnit> AST(ParseAST(MainName)); + ASSERT_TRUE(AST.get()); + ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred()); + + // Reparse and check that the preamble was reused. + ASSERT_TRUE(ReparseAST(AST)); + ASSERT_EQ(AST->getPreambleCounterForTests(), 1U); +} + +TEST_F(PCHPreambleTest, ReparseReusesPreambleAfterUnsavedFileWasCreatedOnDisk) { + std::string Header1 = "//./header1.h"; + std::string MainName = "//./main.cpp"; + AddFile(MainName, R"cpp( +#include "//./header1.h" +int main() { return ZERO; } +)cpp"); + RemapFile(Header1, "#define ZERO 0\n"); + + // Parse with header file provided as unsaved file, which does not exist on + // disk. + std::unique_ptr<ASTUnit> AST(ParseAST(MainName)); + ASSERT_TRUE(AST.get()); + ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred()); + + // Create the unsaved file also on disk and check that preamble was reused. + AddFile(Header1, "#define ZERO 0\n"); + ASSERT_TRUE(ReparseAST(AST)); + ASSERT_EQ(AST->getPreambleCounterForTests(), 1U); +} + +TEST_F(PCHPreambleTest, + ReparseReusesPreambleAfterUnsavedFileWasRemovedFromDisk) { + std::string Header1 = "//./foo/header1.h"; + std::string MainName = "//./main.cpp"; + std::string MainFileContent = R"cpp( +#include "//./foo/header1.h" +int main() { return ZERO; } +)cpp"; + AddFile(MainName, MainFileContent); + AddFile(Header1, "#define ZERO 0\n"); + RemapFile(Header1, "#define ZERO 0\n"); + + // Parse with header file provided as unsaved file, which exists on disk. + std::unique_ptr<ASTUnit> AST(ParseAST(MainName)); + ASSERT_TRUE(AST.get()); + ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred()); + ASSERT_EQ(AST->getPreambleCounterForTests(), 1U); + + // Remove the unsaved file from disk and check that the preamble was reused. + ResetVFS(); + AddFile(MainName, MainFileContent); + ASSERT_TRUE(ReparseAST(AST)); + ASSERT_EQ(AST->getPreambleCounterForTests(), 1U); +} + +TEST_F(PCHPreambleTest, ReparseWithOverriddenFileDoesNotInvalidatePreamble) { + std::string Header1 = "//./header1.h"; + std::string Header2 = "//./header2.h"; + std::string MainName = "//./main.cpp"; + AddFile(Header1, ""); + AddFile(Header2, "#pragma once"); + AddFile(MainName, + "#include \"//./foo/../header1.h\"\n" + "#include \"//./foo/../header2.h\"\n" + "int main() { return ZERO; }"); + RemapFile(Header1, "static const int ZERO = 0;\n"); + + std::unique_ptr<ASTUnit> AST(ParseAST(MainName)); + ASSERT_TRUE(AST.get()); + ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred()); + + unsigned initialCounts[] = { + GetFileReadCount(MainName), + GetFileReadCount(Header1), + GetFileReadCount(Header2) + }; + + ASSERT_TRUE(ReparseAST(AST)); + + ASSERT_NE(initialCounts[0], GetFileReadCount(MainName)); + ASSERT_EQ(initialCounts[1], GetFileReadCount(Header1)); + ASSERT_EQ(initialCounts[2], GetFileReadCount(Header2)); +} + +TEST_F(PCHPreambleTest, ParseWithBom) { + std::string Header = "//./header.h"; + std::string Main = "//./main.cpp"; + AddFile(Header, "int random() { return 4; }"); + AddFile(Main, + "\xef\xbb\xbf" + "#include \"//./header.h\"\n" + "int main() { return random() -2; }"); + + std::unique_ptr<ASTUnit> AST(ParseAST(Main)); + ASSERT_TRUE(AST.get()); + ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred()); + + unsigned HeaderReadCount = GetFileReadCount(Header); + + ASSERT_TRUE(ReparseAST(AST)); + ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred()); + + // Check preamble PCH was really reused + ASSERT_EQ(HeaderReadCount, GetFileReadCount(Header)); + + // Remove BOM + RemapFile(Main, + "#include \"//./header.h\"\n" + "int main() { return random() -2; }"); + + ASSERT_TRUE(ReparseAST(AST)); + ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred()); + + ASSERT_LE(HeaderReadCount, GetFileReadCount(Header)); + HeaderReadCount = GetFileReadCount(Header); + + // Add BOM back + RemapFile(Main, + "\xef\xbb\xbf" + "#include \"//./header.h\"\n" + "int main() { return random() -2; }"); + + ASSERT_TRUE(ReparseAST(AST)); + ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred()); + + ASSERT_LE(HeaderReadCount, GetFileReadCount(Header)); +} + +} // anonymous namespace diff --git a/gnu/llvm/clang/unittests/Frontend/ParsedSourceLocationTest.cpp b/gnu/llvm/clang/unittests/Frontend/ParsedSourceLocationTest.cpp new file mode 100644 index 00000000000..1539005acd8 --- /dev/null +++ b/gnu/llvm/clang/unittests/Frontend/ParsedSourceLocationTest.cpp @@ -0,0 +1,36 @@ +//===- unittests/Frontend/ParsedSourceLocationTest.cpp - ------------------===// +// +// 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/Frontend/CommandLineSourceLoc.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { + +TEST(ParsedSourceRange, ParseTest) { + auto Check = [](StringRef Value, StringRef Filename, unsigned BeginLine, + unsigned BeginColumn, unsigned EndLine, unsigned EndColumn) { + Optional<ParsedSourceRange> PSR = ParsedSourceRange::fromString(Value); + ASSERT_TRUE(PSR); + EXPECT_EQ(PSR->FileName, Filename); + EXPECT_EQ(PSR->Begin.first, BeginLine); + EXPECT_EQ(PSR->Begin.second, BeginColumn); + EXPECT_EQ(PSR->End.first, EndLine); + EXPECT_EQ(PSR->End.second, EndColumn); + }; + + Check("/Users/test/a-b.cpp:1:2", "/Users/test/a-b.cpp", 1, 2, 1, 2); + Check("/Users/test/a-b.cpp:1:2-3:4", "/Users/test/a-b.cpp", 1, 2, 3, 4); + + Check("C:/Users/bob/a-b.cpp:1:2", "C:/Users/bob/a-b.cpp", 1, 2, 1, 2); + Check("C:/Users/bob/a-b.cpp:1:2-3:4", "C:/Users/bob/a-b.cpp", 1, 2, 3, 4); +} + +} // anonymous namespace |