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