• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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