1 /*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "slang_rs_context.h"
18
19 #include <string>
20
21 #include "clang/AST/ASTContext.h"
22 #include "clang/AST/Decl.h"
23 #include "clang/AST/DeclBase.h"
24 #include "clang/AST/Mangle.h"
25 #include "clang/AST/Type.h"
26
27 #include "clang/Basic/Linkage.h"
28 #include "clang/Basic/TargetInfo.h"
29
30 #include "clang/Index/ASTLocation.h"
31
32 #include "llvm/LLVMContext.h"
33
34 #include "llvm/Target/TargetData.h"
35
36 #include "slang.h"
37 #include "slang_assert.h"
38 #include "slang_rs_export_foreach.h"
39 #include "slang_rs_export_func.h"
40 #include "slang_rs_export_type.h"
41 #include "slang_rs_export_var.h"
42 #include "slang_rs_exportable.h"
43 #include "slang_rs_pragma_handler.h"
44 #include "slang_rs_reflection.h"
45
46 namespace slang {
47
RSContext(clang::Preprocessor & PP,clang::ASTContext & Ctx,const clang::TargetInfo & Target,PragmaList * Pragmas,unsigned int TargetAPI,std::vector<std::string> * GeneratedFileNames)48 RSContext::RSContext(clang::Preprocessor &PP,
49 clang::ASTContext &Ctx,
50 const clang::TargetInfo &Target,
51 PragmaList *Pragmas,
52 unsigned int TargetAPI,
53 std::vector<std::string> *GeneratedFileNames)
54 : mPP(PP),
55 mCtx(Ctx),
56 mTarget(Target),
57 mPragmas(Pragmas),
58 mTargetAPI(TargetAPI),
59 mGeneratedFileNames(GeneratedFileNames),
60 mTargetData(NULL),
61 mLLVMContext(llvm::getGlobalContext()),
62 mLicenseNote(NULL),
63 version(0),
64 mMangleCtx(Ctx.createMangleContext()) {
65 slangAssert(mGeneratedFileNames && "Must supply GeneratedFileNames");
66
67 // For #pragma rs export_type
68 PP.AddPragmaHandler(
69 "rs", RSPragmaHandler::CreatePragmaExportTypeHandler(this));
70
71 // For #pragma rs java_package_name
72 PP.AddPragmaHandler(
73 "rs", RSPragmaHandler::CreatePragmaJavaPackageNameHandler(this));
74
75 // For #pragma rs set_reflect_license
76 PP.AddPragmaHandler(
77 "rs", RSPragmaHandler::CreatePragmaReflectLicenseHandler(this));
78
79 // For #pragma version
80 PP.AddPragmaHandler(RSPragmaHandler::CreatePragmaVersionHandler(this));
81
82 // Prepare target data
83 mTargetData = new llvm::TargetData(Target.getTargetDescription());
84
85 return;
86 }
87
processExportVar(const clang::VarDecl * VD)88 bool RSContext::processExportVar(const clang::VarDecl *VD) {
89 slangAssert(!VD->getName().empty() && "Variable name should not be empty");
90
91 // TODO(zonr): some check on variable
92
93 RSExportType *ET = RSExportType::CreateFromDecl(this, VD);
94 if (!ET)
95 return false;
96
97 RSExportVar *EV = new RSExportVar(this, VD, ET);
98 if (EV == NULL)
99 return false;
100 else
101 mExportVars.push_back(EV);
102
103 return true;
104 }
105
processExportFunc(const clang::FunctionDecl * FD)106 bool RSContext::processExportFunc(const clang::FunctionDecl *FD) {
107 slangAssert(!FD->getName().empty() && "Function name should not be empty");
108
109 if (!FD->isThisDeclarationADefinition()) {
110 return true;
111 }
112
113 if (FD->getStorageClass() != clang::SC_None) {
114 fprintf(stderr, "RSContext::processExportFunc : cannot export extern or "
115 "static function '%s'\n", FD->getName().str().c_str());
116 return false;
117 }
118
119 if (RSExportForEach::isRSForEachFunc(mTargetAPI, FD)) {
120 RSExportForEach *EFE = RSExportForEach::Create(this, FD);
121 if (EFE == NULL)
122 return false;
123 else
124 mExportForEach.push_back(EFE);
125 return true;
126 } else if (RSExportForEach::isSpecialRSFunc(FD)) {
127 // Do not reflect specialized RS functions like init or graphics root.
128 if (!RSExportForEach::validateSpecialFuncDecl(mTargetAPI,
129 getDiagnostics(), FD)) {
130 return false;
131 }
132 return true;
133 }
134
135 RSExportFunc *EF = RSExportFunc::Create(this, FD);
136 if (EF == NULL)
137 return false;
138 else
139 mExportFuncs.push_back(EF);
140
141 return true;
142 }
143
144
processExportType(const llvm::StringRef & Name)145 bool RSContext::processExportType(const llvm::StringRef &Name) {
146 clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
147
148 slangAssert(TUDecl != NULL && "Translation unit declaration (top-level "
149 "declaration) is null object");
150
151 const clang::IdentifierInfo *II = mPP.getIdentifierInfo(Name);
152 if (II == NULL)
153 // TODO(zonr): alert identifier @Name mark as an exportable type cannot be
154 // found
155 return false;
156
157 clang::DeclContext::lookup_const_result R = TUDecl->lookup(II);
158 RSExportType *ET = NULL;
159
160 for (clang::DeclContext::lookup_const_iterator I = R.first, E = R.second;
161 I != E;
162 I++) {
163 clang::NamedDecl *const ND = *I;
164 const clang::Type *T = NULL;
165
166 switch (ND->getKind()) {
167 case clang::Decl::Typedef: {
168 T = static_cast<const clang::TypedefDecl*>(
169 ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr();
170 break;
171 }
172 case clang::Decl::Record: {
173 T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl();
174 break;
175 }
176 default: {
177 // unsupported, skip
178 break;
179 }
180 }
181
182 if (T != NULL)
183 ET = RSExportType::Create(this, T);
184 }
185
186 return (ET != NULL);
187 }
188
processExport()189 bool RSContext::processExport() {
190 bool valid = true;
191
192 if (getDiagnostics()->hasErrorOccurred()) {
193 return false;
194 }
195
196 // Export variable
197 clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl();
198 for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
199 DE = TUDecl->decls_end();
200 DI != DE;
201 DI++) {
202 if (DI->getKind() == clang::Decl::Var) {
203 clang::VarDecl *VD = (clang::VarDecl*) (*DI);
204 if (VD->getLinkage() == clang::ExternalLinkage) {
205 if (!processExportVar(VD)) {
206 valid = false;
207 }
208 }
209 } else if (DI->getKind() == clang::Decl::Function) {
210 // Export functions
211 clang::FunctionDecl *FD = (clang::FunctionDecl*) (*DI);
212 if (FD->getLinkage() == clang::ExternalLinkage) {
213 if (!processExportFunc(FD)) {
214 valid = false;
215 }
216 }
217 }
218 }
219
220 // Finally, export type forcely set to be exported by user
221 for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(),
222 EE = mNeedExportTypes.end();
223 EI != EE;
224 EI++) {
225 if (!processExportType(EI->getKey())) {
226 valid = false;
227 }
228 }
229
230 return valid;
231 }
232
insertExportType(const llvm::StringRef & TypeName,RSExportType * ET)233 bool RSContext::insertExportType(const llvm::StringRef &TypeName,
234 RSExportType *ET) {
235 ExportTypeMap::value_type *NewItem =
236 ExportTypeMap::value_type::Create(TypeName.begin(),
237 TypeName.end(),
238 mExportTypes.getAllocator(),
239 ET);
240
241 if (mExportTypes.insert(NewItem)) {
242 return true;
243 } else {
244 free(NewItem);
245 return false;
246 }
247 }
248
reflectToJava(const std::string & OutputPathBase,const std::string & OutputPackageName,const std::string & InputFileName,const std::string & OutputBCFileName,std::string * RealPackageName)249 bool RSContext::reflectToJava(const std::string &OutputPathBase,
250 const std::string &OutputPackageName,
251 const std::string &InputFileName,
252 const std::string &OutputBCFileName,
253 std::string *RealPackageName) {
254 if (RealPackageName != NULL)
255 RealPackageName->clear();
256
257 const std::string &PackageName =
258 ((OutputPackageName.empty()) ? mReflectJavaPackageName :
259 OutputPackageName);
260 if (PackageName.empty()) {
261 std::cerr << "Error: Missing \"#pragma rs "
262 << "java_package_name(com.foo.bar)\" in "
263 << InputFileName << std::endl;
264 return false;
265 }
266
267 // Copy back the really applied package name
268 RealPackageName->assign(PackageName);
269
270 RSReflection *R = new RSReflection(this, mGeneratedFileNames);
271 bool ret = R->reflect(OutputPathBase, PackageName,
272 InputFileName, OutputBCFileName);
273 if (!ret)
274 fprintf(stderr, "RSContext::reflectToJava : failed to do reflection "
275 "(%s)\n", R->getLastError());
276 delete R;
277 return ret;
278 }
279
~RSContext()280 RSContext::~RSContext() {
281 delete mLicenseNote;
282 delete mTargetData;
283 for (ExportableList::iterator I = mExportables.begin(),
284 E = mExportables.end();
285 I != E;
286 I++) {
287 if (!(*I)->isKeep())
288 delete *I;
289 }
290 }
291
292 } // namespace slang
293