slang_rs.cpp revision fcda2352b9e140529f8f3c89f05b10a70c0048b2
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.h" 18 19#include <cstring> 20 21#include "llvm/System/Path.h" 22 23#include "clang/Frontend/FrontendDiagnostic.h" 24 25#include "clang/Sema/SemaDiagnostic.h" 26 27#include "slang_rs_backend.h" 28#include "slang_rs_context.h" 29#include "slang_rs_export_type.h" 30 31using namespace slang; 32 33#define RS_HEADER_SUFFIX "rsh" 34 35/* RS_HEADER_ENTRY(name, default_included) */ 36#define ENUM_RS_HEADER() \ 37 RS_HEADER_ENTRY(rs_types, 1) \ 38 RS_HEADER_ENTRY(rs_cl, 1) \ 39 RS_HEADER_ENTRY(rs_core, 1) \ 40 RS_HEADER_ENTRY(rs_math, 1) \ 41 RS_HEADER_ENTRY(rs_graphics, 0) 42 43bool SlangRS::reflectToJava(const std::string &OutputPathBase, 44 const std::string &OutputPackageName, 45 std::string *RealPackageName) { 46 return mRSContext->reflectToJava(OutputPathBase, 47 OutputPackageName, 48 getInputFileName(), 49 getOutputFileName(), 50 RealPackageName); 51} 52 53bool SlangRS::generateBitcodeAccessor(const std::string &OutputPathBase, 54 const std::string &PackageName) { 55 RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext; 56 57 BCAccessorContext.rsFileName = getInputFileName().c_str(); 58 BCAccessorContext.bcFileName = getOutputFileName().c_str(); 59 BCAccessorContext.reflectPath = OutputPathBase.c_str(); 60 BCAccessorContext.packageName = PackageName.c_str(); 61 BCAccessorContext.bcStorage = BCST_JAVA_CODE; // Must be BCST_JAVA_CODE 62 63 return RSSlangReflectUtils::GenerateBitCodeAccessor(BCAccessorContext); 64} 65 66bool SlangRS::checkODR(const char *CurInputFile) { 67 for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(), 68 E = mRSContext->exportable_end(); 69 I != E; 70 I++) { 71 RSExportable *E = *I; 72 if (E->getKind() != RSExportable::EX_TYPE) 73 continue; 74 75 RSExportType *ET = static_cast<RSExportType *>(E); 76 if (ET->getClass() != RSExportType::ExportClassRecord) 77 continue; 78 79 RSExportRecordType *ERT = static_cast<RSExportRecordType *>(ET); 80 81 // Artificial record types (create by us not by user in the source) always 82 // conforms the ODR. 83 if (ERT->isArtificial()) 84 continue; 85 86 // Key to lookup ERT in ReflectedDefinitions 87 llvm::StringRef RDKey(ERT->getName()); 88 ReflectedDefinitionListTy::const_iterator RD = 89 ReflectedDefinitions.find(RDKey); 90 91 if (RD != ReflectedDefinitions.end()) { 92 const RSExportRecordType *Reflected = RD->getValue().first; 93 // There's a record (struct) with the same name reflected before. Enforce 94 // ODR checking - the Reflected must hold *exactly* the same "definition" 95 // as the one defined previously. We say two record types A and B have the 96 // same definition iff: 97 // 98 // struct A { struct B { 99 // Type(a1) a1, Type(b1) b1, 100 // Type(a2) a2, Type(b1) b2, 101 // ... ... 102 // Type(aN) aN Type(b3) b3, 103 // }; } 104 // Cond. #1. They have same number of fields, i.e., N = M; 105 // Cond. #2. for (i := 1 to N) 106 // Type(ai) = Type(bi) must hold; 107 // Cond. #3. for (i := 1 to N) 108 // Name(ai) = Name(bi) must hold; 109 // 110 // where, 111 // Type(F) = the type of field F and 112 // Name(F) = the field name. 113 114 bool PassODR = false; 115 // Cond. #1 and Cond. #2 116 if (Reflected->equals(ERT)) { 117 // Cond #3. 118 RSExportRecordType::const_field_iterator AI = Reflected->fields_begin(), 119 BI = ERT->fields_begin(); 120 121 for (unsigned i = 0, e = Reflected->getFields().size(); i != e; i++) { 122 if ((*AI)->getName() != (*BI)->getName()) 123 break; 124 AI++; 125 BI++; 126 } 127 PassODR = (AI == (Reflected->fields_end())); 128 } 129 130 if (!PassODR) { 131 getDiagnostics().Report(mDiagErrorODR) << Reflected->getName() 132 << getInputFileName() 133 << RD->getValue().second; 134 return false; 135 } 136 } else { 137 llvm::StringMapEntry<ReflectedDefinitionTy> *ME = 138 llvm::StringMapEntry<ReflectedDefinitionTy>::Create(RDKey.begin(), 139 RDKey.end()); 140 ME->setValue(std::make_pair(ERT, CurInputFile)); 141 142 if (!ReflectedDefinitions.insert(ME)) 143 delete ME; 144 145 // Take the ownership of ERT such that it won't be freed in ~RSContext(). 146 ERT->keep(); 147 } 148 } 149 return true; 150} 151 152void SlangRS::initDiagnostic() { 153 clang::Diagnostic &Diag = getDiagnostics(); 154 if (Diag.setDiagnosticGroupMapping("implicit-function-declaration", 155 clang::diag::MAP_ERROR)) 156 Diag.Report(clang::diag::warn_unknown_warning_option) 157 << "implicit-function-declaration"; 158 159 Diag.setDiagnosticMapping( 160 clang::diag::ext_typecheck_convert_discards_qualifiers, 161 clang::diag::MAP_ERROR); 162 163 mDiagErrorInvalidOutputDepParameter = 164 Diag.getCustomDiagID(clang::Diagnostic::Error, 165 "invalid parameter for output dependencies files."); 166 167 mDiagErrorODR = 168 Diag.getCustomDiagID(clang::Diagnostic::Error, 169 "type '%0' in different translation unit (%1 v.s. " 170 "%2) has incompatible type definition"); 171 172 return; 173} 174 175void SlangRS::initPreprocessor() { 176 clang::Preprocessor &PP = getPreprocessor(); 177 178 std::string RSH; 179#define RS_HEADER_ENTRY(name, default_included) \ 180 if (default_included) \ 181 RSH.append("#include \"" #name "."RS_HEADER_SUFFIX "\"\n"); 182 ENUM_RS_HEADER() 183#undef RS_HEADER_ENTRY 184 PP.setPredefines(RSH); 185 186 return; 187} 188 189void SlangRS::initASTContext() { 190 mRSContext = new RSContext(&getPreprocessor(), 191 &getASTContext(), 192 &getTargetInfo()); 193 return; 194} 195 196clang::ASTConsumer 197*SlangRS::createBackend(const clang::CodeGenOptions& CodeGenOpts, 198 llvm::raw_ostream *OS, 199 Slang::OutputType OT) { 200 return new RSBackend(mRSContext, 201 getDiagnostics(), 202 CodeGenOpts, 203 getTargetOptions(), 204 mPragmas, 205 OS, 206 OT, 207 getSourceManager(), 208 mAllowRSPrefix); 209} 210 211bool SlangRS::IsRSHeaderFile(const char *File) { 212#define RS_HEADER_ENTRY(name, default_included) \ 213 if (::strcmp(File, #name "."RS_HEADER_SUFFIX) == 0) \ 214 return true; 215ENUM_RS_HEADER() 216#undef RS_HEADER_ENTRY 217 return false; 218} 219 220bool SlangRS::IsFunctionInRSHeaderFile(const clang::FunctionDecl *FD, 221 const clang::SourceManager &SourceMgr) { 222 clang::FullSourceLoc FSL(FD->getLocStart(), SourceMgr); 223 clang::PresumedLoc PLoc = SourceMgr.getPresumedLoc(FSL); 224 llvm::sys::Path HeaderFilename(PLoc.getFilename()); 225 226 return IsRSHeaderFile(HeaderFilename.getLast().data()); 227} 228 229SlangRS::SlangRS() : Slang(), mRSContext(NULL), mAllowRSPrefix(false) { 230 return; 231} 232 233bool SlangRS::compile( 234 const std::list<std::pair<const char*, const char*> > &IOFiles, 235 const std::list<std::pair<const char*, const char*> > &DepFiles, 236 const std::vector<std::string> &IncludePaths, 237 const std::vector<std::string> &AdditionalDepTargets, 238 Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage, 239 bool AllowRSPrefix, bool OutputDep, 240 const std::string &JavaReflectionPathBase, 241 const std::string &JavaReflectionPackageName) { 242 if (IOFiles.empty()) 243 return true; 244 245 if (OutputDep && (DepFiles.size() != IOFiles.size())) { 246 getDiagnostics().Report(mDiagErrorInvalidOutputDepParameter); 247 return false; 248 } 249 250 std::string RealPackageName; 251 252 const char *InputFile, *OutputFile, *BCOutputFile, *DepOutputFile; 253 std::list<std::pair<const char*, const char*> >::const_iterator 254 IOFileIter = IOFiles.begin(), DepFileIter = DepFiles.begin(); 255 256 setIncludePaths(IncludePaths); 257 setOutputType(OutputType); 258 if (OutputDep) 259 setAdditionalDepTargets(AdditionalDepTargets); 260 261 mAllowRSPrefix = AllowRSPrefix; 262 263 for (unsigned i = 0, e = IOFiles.size(); i != e; i++) { 264 InputFile = IOFileIter->first; 265 OutputFile = IOFileIter->second; 266 267 reset(); 268 269 if (!setInputSource(InputFile)) 270 return false; 271 272 if (!setOutput(OutputFile)) 273 return false; 274 275 if (OutputDep) { 276 BCOutputFile = DepFileIter->first; 277 DepOutputFile = DepFileIter->second; 278 279 setDepTargetBC(BCOutputFile); 280 281 if (!setDepOutput(DepOutputFile)) 282 return false; 283 284 if (generateDepFile() > 0) 285 return false; 286 287 DepFileIter++; 288 } 289 290 if (Slang::compile() > 0) 291 return false; 292 293 if (OutputType != Slang::OT_Dependency) { 294 if (!reflectToJava(JavaReflectionPathBase, 295 JavaReflectionPackageName, 296 &RealPackageName)) 297 return false; 298 299 if ((OutputType == Slang::OT_Bitcode) && 300 (BitcodeStorage == BCST_JAVA_CODE) && 301 !generateBitcodeAccessor(JavaReflectionPathBase, 302 RealPackageName.c_str())) 303 return false; 304 } 305 306 if (!checkODR(InputFile)) 307 return false; 308 309 IOFileIter++; 310 } 311 312 return true; 313} 314 315void SlangRS::reset() { 316 delete mRSContext; 317 mRSContext = NULL; 318 Slang::reset(); 319 return; 320} 321 322SlangRS::~SlangRS() { 323 delete mRSContext; 324 for (ReflectedDefinitionListTy::iterator I = ReflectedDefinitions.begin(), 325 E = ReflectedDefinitions.end(); 326 I != E; 327 I++) { 328 delete I->getValue().first; 329 } 330 return; 331} 332