slang_rs_context.cpp revision 641558f02fe6ce0ee3ae5076eb366c25e2ad5903
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 "llvm/LLVMContext.h"
20#include "llvm/Target/TargetData.h"
21
22#include "clang/Basic/TargetInfo.h"
23#include "clang/Basic/Linkage.h"
24#include "clang/AST/Type.h"
25#include "clang/AST/Decl.h"
26#include "clang/AST/DeclBase.h"
27#include "clang/AST/ASTContext.h"
28#include "clang/Index/ASTLocation.h"
29
30#include "slang.h"
31#include "slang_rs_reflection.h"
32#include "slang_rs_exportable.h"
33#include "slang_rs_export_var.h"
34#include "slang_rs_export_func.h"
35#include "slang_rs_export_type.h"
36#include "slang_rs_pragma_handler.h"
37
38using namespace slang;
39
40RSContext::RSContext(clang::Preprocessor *PP,
41                     clang::ASTContext *Ctx,
42                     const clang::TargetInfo *Target)
43    : mPP(PP),
44      mCtx(Ctx),
45      mTarget(Target),
46      mTargetData(NULL),
47      mLLVMContext(llvm::getGlobalContext()),
48      mExportAllNonStaticVars(true),
49      mExportAllNonStaticFuncs(false),
50      mLicenseNote(NULL) {
51  // For #pragma rs export_var
52  PP->AddPragmaHandler(
53      "rs", RSPragmaHandler::CreatePragmaExportVarHandler(this));
54
55  // For #pragma rs export_var_all
56  PP->AddPragmaHandler(
57      "rs", RSPragmaHandler::CreatePragmaExportVarAllHandler(this));
58
59  // For #pragma rs export_func
60  PP->AddPragmaHandler(
61      "rs", RSPragmaHandler::CreatePragmaExportFuncHandler(this));
62
63  // For #pragma rs export_func_all
64  PP->AddPragmaHandler(
65      "rs", RSPragmaHandler::CreatePragmaExportFuncAllHandler(this));
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  // Prepare target data
80  mTargetData = new llvm::TargetData(Slang::TargetDescription);
81
82  return;
83}
84
85bool RSContext::processExportVar(const clang::VarDecl *VD) {
86  assert(!VD->getName().empty() && "Variable name should not be empty");
87
88  // TODO(zonr): some check on variable
89
90  RSExportType *ET = RSExportType::CreateFromDecl(this, VD);
91  if (!ET)
92    return false;
93
94  RSExportVar *EV = new RSExportVar(this, VD, ET);
95  if (EV == NULL)
96    return false;
97  else
98    mExportVars.push_back(EV);
99
100  return true;
101}
102
103bool RSContext::processExportFunc(const clang::FunctionDecl *FD) {
104  assert(!FD->getName().empty() && "Function name should not be empty");
105
106  if (!FD->isThisDeclarationADefinition())
107    return false;
108
109  if (FD->getStorageClass() != clang::SC_None) {
110    fprintf(stderr, "RSContext::processExportFunc : cannot export extern or "
111                    "static function '%s'\n", FD->getName().str().c_str());
112    return false;
113  }
114
115  RSExportFunc *EF = RSExportFunc::Create(this, FD);
116  if (EF == NULL)
117    return false;
118  else
119    mExportFuncs.push_back(EF);
120
121  return true;
122}
123
124
125bool RSContext::processExportType(const llvm::StringRef &Name) {
126  clang::TranslationUnitDecl *TUDecl = mCtx->getTranslationUnitDecl();
127
128  assert(TUDecl != NULL && "Translation unit declaration (top-level "
129                           "declaration) is null object");
130
131  const clang::IdentifierInfo *II = mPP->getIdentifierInfo(Name);
132  if (II == NULL)
133    // TODO(zonr): alert identifier @Name mark as an exportable type cannot be
134    //             found
135    return false;
136
137  clang::DeclContext::lookup_const_result R = TUDecl->lookup(II);
138  RSExportType *ET = NULL;
139
140  RSExportPointerType::IntegerType = mCtx->IntTy.getTypePtr();
141
142  for (clang::DeclContext::lookup_const_iterator I = R.first, E = R.second;
143       I != E;
144       I++) {
145    clang::NamedDecl *const ND = *I;
146    const clang::Type *T = NULL;
147
148    switch (ND->getKind()) {
149      case clang::Decl::Typedef: {
150        T = static_cast<const clang::TypedefDecl*>(
151            ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr();
152        break;
153      }
154      case clang::Decl::Record: {
155        T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl();
156        break;
157      }
158      default: {
159        // unsupported, skip
160        break;
161      }
162    }
163
164    if (T != NULL)
165      ET = RSExportType::Create(this, T);
166  }
167
168  RSExportPointerType::IntegerType = NULL;
169
170  return (ET != NULL);
171}
172
173void RSContext::processExport() {
174  if (mNeedExportVars.empty() &&
175      mNeedExportFuncs.empty() &&
176      !mExportAllNonStaticVars && !mExportAllNonStaticFuncs) {
177    fprintf(stderr, "note: No reflection because there are no #pragma "
178                    "rs export_var(...), #pragma rs export_func(...), "
179                    "#pragma rs export_var_all, or #pragma rs "
180                    "export_func_all\n");
181  }
182
183  // Export variable
184  clang::TranslationUnitDecl *TUDecl = mCtx->getTranslationUnitDecl();
185  for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
186           DE = TUDecl->decls_end();
187       DI != TUDecl->decls_end();
188       DI++) {
189    if (DI->getKind() == clang::Decl::Var) {
190      clang::VarDecl *VD = (clang::VarDecl*) (*DI);
191      if (mExportAllNonStaticVars &&
192          (VD->getLinkage() == clang::ExternalLinkage)) {
193        if (!processExportVar(VD)) {
194          fprintf(stderr, "RSContext::processExport : failed to export var "
195                          "'%s'\n", VD->getNameAsString().c_str());
196        }
197      } else {
198        NeedExportVarSet::iterator EI = mNeedExportVars.find(VD->getName());
199        if (EI != mNeedExportVars.end() && processExportVar(VD)) {
200          mNeedExportVars.erase(EI);
201        }
202      }
203    } else if (DI->getKind() == clang::Decl::Function) {
204      // Export functions
205      clang::FunctionDecl *FD = (clang::FunctionDecl*) (*DI);
206      if (mExportAllNonStaticFuncs &&
207          (FD->getLinkage() == clang::ExternalLinkage)) {
208        if (!processExportFunc(FD)) {
209          fprintf(stderr, "RSContext::processExport : failed to export func "
210                          "'%s'\n", FD->getNameAsString().c_str());
211        }
212      } else {
213        NeedExportFuncSet::iterator EI = mNeedExportFuncs.find(FD->getName());
214        if (EI != mNeedExportFuncs.end() && processExportFunc(FD))
215          mNeedExportFuncs.erase(EI);
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      fprintf(stderr, "RSContext::processExport : failed to export type "
227              "'%s'\n", EI->getKey().str().c_str());
228    }
229  }
230
231  return;
232}
233
234bool RSContext::insertExportType(const llvm::StringRef &TypeName,
235                                 RSExportType *ET) {
236  ExportTypeMap::value_type *NewItem =
237      ExportTypeMap::value_type::Create(TypeName.begin(),
238                                        TypeName.end(),
239                                        mExportTypes.getAllocator(),
240                                        ET);
241
242  if (mExportTypes.insert(NewItem)) {
243    return true;
244  } else {
245    free(NewItem);
246    return false;
247  }
248}
249
250bool RSContext::reflectToJava(const std::string &OutputPathBase,
251                              const std::string &OutputPackageName,
252                              const std::string &InputFileName,
253                              const std::string &OutputBCFileName,
254                              std::string *RealPackageName) {
255  if (RealPackageName != NULL)
256    RealPackageName->clear();
257
258  const std::string &PackageName =
259      ((OutputPackageName.empty()) ? mReflectJavaPackageName :
260                                     OutputPackageName);
261  if (PackageName.empty())
262    // no package name, just return
263    return true;
264
265  // Copy back the really applied package name
266  RealPackageName->assign(PackageName);
267
268  RSReflection *R = new RSReflection(this);
269  bool ret = R->reflect(OutputPathBase, PackageName,
270                        InputFileName, OutputBCFileName);
271  if (!ret)
272    fprintf(stderr, "RSContext::reflectToJava : failed to do reflection "
273                    "(%s)\n", R->getLastError());
274  delete R;
275  return ret;
276}
277
278RSContext::~RSContext() {
279  delete mLicenseNote;
280  delete mTargetData;
281  for (ExportableList::iterator I = mExportables.begin(),
282          E = mExportables.end();
283       I != E;
284       I++) {
285    if (!(*I)->isKeep())
286      delete *I;
287  }
288}
289