1 //===- unittests/Interpreter/InterpreterTest.cpp --- Interpreter 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Unit tests for Clang's Interpreter library. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/Interpreter/Interpreter.h" 14 15 #include "clang/AST/Decl.h" 16 #include "clang/AST/DeclGroup.h" 17 #include "clang/Frontend/CompilerInstance.h" 18 #include "clang/Frontend/TextDiagnosticPrinter.h" 19 20 #include "llvm/ADT/ArrayRef.h" 21 22 #include "gmock/gmock.h" 23 #include "gtest/gtest.h" 24 25 using namespace clang; 26 27 namespace { 28 using Args = std::vector<const char *>; 29 static std::unique_ptr<Interpreter> 30 createInterpreter(const Args &ExtraArgs = {}, 31 DiagnosticConsumer *Client = nullptr) { 32 Args ClangArgs = {"-Xclang", "-emit-llvm-only"}; 33 ClangArgs.insert(ClangArgs.end(), ExtraArgs.begin(), ExtraArgs.end()); 34 auto CI = cantFail(clang::IncrementalCompilerBuilder::create(ClangArgs)); 35 if (Client) 36 CI->getDiagnostics().setClient(Client, /*ShouldOwnClient=*/false); 37 return cantFail(clang::Interpreter::create(std::move(CI))); 38 } 39 40 static size_t DeclsSize(TranslationUnitDecl *PTUDecl) { 41 return std::distance(PTUDecl->decls().begin(), PTUDecl->decls().end()); 42 } 43 44 TEST(InterpreterTest, Sanity) { 45 std::unique_ptr<Interpreter> Interp = createInterpreter(); 46 47 using PTU = PartialTranslationUnit; 48 49 PTU &R1(cantFail(Interp->Parse("void g(); void g() {}"))); 50 EXPECT_EQ(2U, DeclsSize(R1.TUPart)); 51 52 PTU &R2(cantFail(Interp->Parse("int i;"))); 53 EXPECT_EQ(1U, DeclsSize(R2.TUPart)); 54 } 55 56 static std::string DeclToString(Decl *D) { 57 return llvm::cast<NamedDecl>(D)->getQualifiedNameAsString(); 58 } 59 60 TEST(InterpreterTest, IncrementalInputTopLevelDecls) { 61 std::unique_ptr<Interpreter> Interp = createInterpreter(); 62 auto R1 = Interp->Parse("int var1 = 42; int f() { return var1; }"); 63 // gtest doesn't expand into explicit bool conversions. 64 EXPECT_TRUE(!!R1); 65 auto R1DeclRange = R1->TUPart->decls(); 66 EXPECT_EQ(2U, DeclsSize(R1->TUPart)); 67 EXPECT_EQ("var1", DeclToString(*R1DeclRange.begin())); 68 EXPECT_EQ("f", DeclToString(*(++R1DeclRange.begin()))); 69 70 auto R2 = Interp->Parse("int var2 = f();"); 71 EXPECT_TRUE(!!R2); 72 auto R2DeclRange = R2->TUPart->decls(); 73 EXPECT_EQ(1U, DeclsSize(R2->TUPart)); 74 EXPECT_EQ("var2", DeclToString(*R2DeclRange.begin())); 75 } 76 77 TEST(InterpreterTest, Errors) { 78 Args ExtraArgs = {"-Xclang", "-diagnostic-log-file", "-Xclang", "-"}; 79 80 // Create the diagnostic engine with unowned consumer. 81 std::string DiagnosticOutput; 82 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); 83 auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>( 84 DiagnosticsOS, new DiagnosticOptions()); 85 86 auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get()); 87 auto Err = Interp->Parse("intentional_error v1 = 42; ").takeError(); 88 using ::testing::HasSubstr; 89 EXPECT_THAT(DiagnosticsOS.str(), 90 HasSubstr("error: unknown type name 'intentional_error'")); 91 EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err))); 92 93 auto RecoverErr = Interp->Parse("int var1 = 42;"); 94 EXPECT_TRUE(!!RecoverErr); 95 } 96 97 // Here we test whether the user can mix declarations and statements. The 98 // interpreter should be smart enough to recognize the declarations from the 99 // statements and wrap the latter into a declaration, producing valid code. 100 TEST(InterpreterTest, DeclsAndStatements) { 101 Args ExtraArgs = {"-Xclang", "-diagnostic-log-file", "-Xclang", "-"}; 102 103 // Create the diagnostic engine with unowned consumer. 104 std::string DiagnosticOutput; 105 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); 106 auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>( 107 DiagnosticsOS, new DiagnosticOptions()); 108 109 auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get()); 110 auto R1 = Interp->Parse( 111 "int var1 = 42; extern \"C\" int printf(const char*, ...);"); 112 // gtest doesn't expand into explicit bool conversions. 113 EXPECT_TRUE(!!R1); 114 115 auto *PTU1 = R1->TUPart; 116 EXPECT_EQ(2U, DeclsSize(PTU1)); 117 118 // FIXME: Add support for wrapping and running statements. 119 auto R2 = Interp->Parse("var1++; printf(\"var1 value %d\\n\", var1);"); 120 EXPECT_FALSE(!!R2); 121 using ::testing::HasSubstr; 122 EXPECT_THAT(DiagnosticsOS.str(), 123 HasSubstr("error: unknown type name 'var1'")); 124 auto Err = R2.takeError(); 125 EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err))); 126 } 127 128 } // end anonymous namespace 129