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/AST/Mangle.h"
18 #include "clang/Frontend/CompilerInstance.h"
19 #include "clang/Frontend/TextDiagnosticPrinter.h"
20 #include "clang/Sema/Lookup.h"
21 #include "clang/Sema/Sema.h"
22 
23 #include "llvm/Support/TargetSelect.h"
24 
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 
28 using namespace clang;
29 
30 namespace {
31 using Args = std::vector<const char *>;
32 static std::unique_ptr<Interpreter>
33 createInterpreter(const Args &ExtraArgs = {},
34                   DiagnosticConsumer *Client = nullptr) {
35   Args ClangArgs = {"-Xclang", "-emit-llvm-only"};
36   ClangArgs.insert(ClangArgs.end(), ExtraArgs.begin(), ExtraArgs.end());
37   auto CI = cantFail(clang::IncrementalCompilerBuilder::create(ClangArgs));
38   if (Client)
39     CI->getDiagnostics().setClient(Client, /*ShouldOwnClient=*/false);
40   return cantFail(clang::Interpreter::create(std::move(CI)));
41 }
42 
43 static size_t DeclsSize(TranslationUnitDecl *PTUDecl) {
44   return std::distance(PTUDecl->decls().begin(), PTUDecl->decls().end());
45 }
46 
47 TEST(InterpreterTest, Sanity) {
48   std::unique_ptr<Interpreter> Interp = createInterpreter();
49 
50   using PTU = PartialTranslationUnit;
51 
52   PTU &R1(cantFail(Interp->Parse("void g(); void g() {}")));
53   EXPECT_EQ(2U, DeclsSize(R1.TUPart));
54 
55   PTU &R2(cantFail(Interp->Parse("int i;")));
56   EXPECT_EQ(1U, DeclsSize(R2.TUPart));
57 }
58 
59 static std::string DeclToString(Decl *D) {
60   return llvm::cast<NamedDecl>(D)->getQualifiedNameAsString();
61 }
62 
63 TEST(InterpreterTest, IncrementalInputTopLevelDecls) {
64   std::unique_ptr<Interpreter> Interp = createInterpreter();
65   auto R1 = Interp->Parse("int var1 = 42; int f() { return var1; }");
66   // gtest doesn't expand into explicit bool conversions.
67   EXPECT_TRUE(!!R1);
68   auto R1DeclRange = R1->TUPart->decls();
69   EXPECT_EQ(2U, DeclsSize(R1->TUPart));
70   EXPECT_EQ("var1", DeclToString(*R1DeclRange.begin()));
71   EXPECT_EQ("f", DeclToString(*(++R1DeclRange.begin())));
72 
73   auto R2 = Interp->Parse("int var2 = f();");
74   EXPECT_TRUE(!!R2);
75   auto R2DeclRange = R2->TUPart->decls();
76   EXPECT_EQ(1U, DeclsSize(R2->TUPart));
77   EXPECT_EQ("var2", DeclToString(*R2DeclRange.begin()));
78 }
79 
80 TEST(InterpreterTest, Errors) {
81   Args ExtraArgs = {"-Xclang", "-diagnostic-log-file", "-Xclang", "-"};
82 
83   // Create the diagnostic engine with unowned consumer.
84   std::string DiagnosticOutput;
85   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
86   auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
87       DiagnosticsOS, new DiagnosticOptions());
88 
89   auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
90   auto Err = Interp->Parse("intentional_error v1 = 42; ").takeError();
91   using ::testing::HasSubstr;
92   EXPECT_THAT(DiagnosticsOS.str(),
93               HasSubstr("error: unknown type name 'intentional_error'"));
94   EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err)));
95 
96   auto RecoverErr = Interp->Parse("int var1 = 42;");
97   EXPECT_TRUE(!!RecoverErr);
98 }
99 
100 // Here we test whether the user can mix declarations and statements. The
101 // interpreter should be smart enough to recognize the declarations from the
102 // statements and wrap the latter into a declaration, producing valid code.
103 TEST(InterpreterTest, DeclsAndStatements) {
104   Args ExtraArgs = {"-Xclang", "-diagnostic-log-file", "-Xclang", "-"};
105 
106   // Create the diagnostic engine with unowned consumer.
107   std::string DiagnosticOutput;
108   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
109   auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
110       DiagnosticsOS, new DiagnosticOptions());
111 
112   auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
113   auto R1 = Interp->Parse(
114       "int var1 = 42; extern \"C\" int printf(const char*, ...);");
115   // gtest doesn't expand into explicit bool conversions.
116   EXPECT_TRUE(!!R1);
117 
118   auto *PTU1 = R1->TUPart;
119   EXPECT_EQ(2U, DeclsSize(PTU1));
120 
121   // FIXME: Add support for wrapping and running statements.
122   auto R2 = Interp->Parse("var1++; printf(\"var1 value %d\\n\", var1);");
123   EXPECT_FALSE(!!R2);
124   using ::testing::HasSubstr;
125   EXPECT_THAT(DiagnosticsOS.str(),
126               HasSubstr("error: unknown type name 'var1'"));
127   auto Err = R2.takeError();
128   EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err)));
129 }
130 
131 static std::string MangleName(NamedDecl *ND) {
132   ASTContext &C = ND->getASTContext();
133   std::unique_ptr<MangleContext> MangleC(C.createMangleContext());
134   std::string mangledName;
135   llvm::raw_string_ostream RawStr(mangledName);
136   MangleC->mangleName(ND, RawStr);
137   return RawStr.str();
138 }
139 
140 struct LLVMInitRAII {
141   LLVMInitRAII() {
142     llvm::InitializeNativeTarget();
143     llvm::InitializeNativeTargetAsmPrinter();
144   }
145   ~LLVMInitRAII() { llvm::llvm_shutdown(); }
146 } LLVMInit;
147 
148 #ifdef _AIX
149 TEST(IncrementalProcessing, DISABLED_FindMangledNameSymbol) {
150 #else
151 TEST(IncrementalProcessing, FindMangledNameSymbol) {
152 #endif
153 
154   std::unique_ptr<Interpreter> Interp = createInterpreter();
155 
156   auto &PTU(cantFail(Interp->Parse("int f(const char*) {return 0;}")));
157   EXPECT_EQ(1U, DeclsSize(PTU.TUPart));
158   auto R1DeclRange = PTU.TUPart->decls();
159 
160   NamedDecl *FD = cast<FunctionDecl>(*R1DeclRange.begin());
161   // Lower the PTU
162   if (llvm::Error Err = Interp->Execute(PTU)) {
163     // We cannot execute on the platform.
164     consumeError(std::move(Err));
165     return;
166   }
167 
168   std::string MangledName = MangleName(FD);
169   auto Addr = cantFail(Interp->getSymbolAddress(MangledName));
170   EXPECT_NE(0U, Addr);
171   GlobalDecl GD(FD);
172   EXPECT_EQ(Addr, cantFail(Interp->getSymbolAddress(GD)));
173 }
174 
175 static void *AllocateObject(TypeDecl *TD, Interpreter &Interp) {
176   std::string Name = TD->getQualifiedNameAsString();
177   const clang::Type *RDTy = TD->getTypeForDecl();
178   clang::ASTContext &C = Interp.getCompilerInstance()->getASTContext();
179   size_t Size = C.getTypeSize(RDTy);
180   void *Addr = malloc(Size);
181 
182   // Tell the interpreter to call the default ctor with this memory. Synthesize:
183   // new (loc) ClassName;
184   static unsigned Counter = 0;
185   std::stringstream SS;
186   SS << "auto _v" << Counter++ << " = "
187      << "new ((void*)"
188      // Windows needs us to prefix the hexadecimal value of a pointer with '0x'.
189      << std::hex << std::showbase << (size_t)Addr << ")" << Name << "();";
190 
191   auto R = Interp.ParseAndExecute(SS.str());
192   if (!R)
193     return nullptr;
194 
195   return Addr;
196 }
197 
198 static NamedDecl *LookupSingleName(Interpreter &Interp, const char *Name) {
199   Sema &SemaRef = Interp.getCompilerInstance()->getSema();
200   ASTContext &C = SemaRef.getASTContext();
201   DeclarationName DeclName = &C.Idents.get(Name);
202   LookupResult R(SemaRef, DeclName, SourceLocation(), Sema::LookupOrdinaryName);
203   SemaRef.LookupName(R, SemaRef.TUScope);
204   assert(!R.empty());
205   return R.getFoundDecl();
206 }
207 
208 #ifdef _AIX
209 TEST(IncrementalProcessing, DISABLED_InstantiateTemplate) {
210 #else
211 TEST(IncrementalProcessing, InstantiateTemplate) {
212 #endif
213   // FIXME: We cannot yet handle delayed template parsing. If we run with
214   // -fdelayed-template-parsing we try adding the newly created decl to the
215   // active PTU which causes an assert.
216   std::vector<const char *> Args = {"-fno-delayed-template-parsing"};
217   std::unique_ptr<Interpreter> Interp = createInterpreter(Args);
218 
219   llvm::cantFail(Interp->Parse("void* operator new(__SIZE_TYPE__, void* __p);"
220                                "extern \"C\" int printf(const char*,...);"
221                                "class A {};"
222                                "struct B {"
223                                "  template<typename T>"
224                                "  static int callme(T) { return 42; }"
225                                "};"));
226   auto &PTU = llvm::cantFail(Interp->Parse("auto _t = &B::callme<A*>;"));
227   auto PTUDeclRange = PTU.TUPart->decls();
228   EXPECT_EQ(1, std::distance(PTUDeclRange.begin(), PTUDeclRange.end()));
229 
230   // Lower the PTU
231   if (llvm::Error Err = Interp->Execute(PTU)) {
232     // We cannot execute on the platform.
233     consumeError(std::move(Err));
234     return;
235   }
236 
237   TypeDecl *TD = cast<TypeDecl>(LookupSingleName(*Interp, "A"));
238   void *NewA = AllocateObject(TD, *Interp);
239 
240   // Find back the template specialization
241   VarDecl *VD = static_cast<VarDecl *>(*PTUDeclRange.begin());
242   UnaryOperator *UO = llvm::cast<UnaryOperator>(VD->getInit());
243   NamedDecl *TmpltSpec = llvm::cast<DeclRefExpr>(UO->getSubExpr())->getDecl();
244 
245   std::string MangledName = MangleName(TmpltSpec);
246   typedef int (*TemplateSpecFn)(void *);
247   auto fn = (TemplateSpecFn)cantFail(Interp->getSymbolAddress(MangledName));
248   EXPECT_EQ(42, fn(NewA));
249 }
250 
251 } // end anonymous namespace
252