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