Home | History | Annotate | Download | only in slang
      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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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