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