diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/ARCMigrate')
20 files changed, 835 insertions, 294 deletions
diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMT.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMT.cpp index f1d947d..6e1b0e5 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMT.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMT.cpp @@ -10,6 +10,7 @@ #include "Internals.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Frontend/Utils.h" #include "clang/AST/ASTConsumer.h" #include "clang/Rewrite/Rewriter.h" @@ -18,12 +19,10 @@ #include "clang/Lex/Preprocessor.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/ADT/Triple.h" - using namespace clang; using namespace arcmt; -using llvm::StringRef; -bool CapturedDiagList::clearDiagnostic(llvm::ArrayRef<unsigned> IDs, +bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) { if (range.isInvalid()) return false; @@ -39,7 +38,7 @@ bool CapturedDiagList::clearDiagnostic(llvm::ArrayRef<unsigned> IDs, diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { cleared = true; ListTy::iterator eraseS = I++; - while (I != List.end() && I->getLevel() == Diagnostic::Note) + while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note) ++I; // Clear the diagnostic and any notes following it. List.erase(eraseS, I); @@ -52,7 +51,7 @@ bool CapturedDiagList::clearDiagnostic(llvm::ArrayRef<unsigned> IDs, return cleared; } -bool CapturedDiagList::hasDiagnostic(llvm::ArrayRef<unsigned> IDs, +bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) const { if (range.isInvalid()) return false; @@ -74,14 +73,14 @@ bool CapturedDiagList::hasDiagnostic(llvm::ArrayRef<unsigned> IDs, return false; } -void CapturedDiagList::reportDiagnostics(Diagnostic &Diags) const { +void CapturedDiagList::reportDiagnostics(DiagnosticsEngine &Diags) const { for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) Diags.Report(*I); } bool CapturedDiagList::hasErrors() const { for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) - if (I->getLevel() >= Diagnostic::Error) + if (I->getLevel() >= DiagnosticsEngine::Error) return true; return false; @@ -89,18 +88,18 @@ bool CapturedDiagList::hasErrors() const { namespace { -class CaptureDiagnosticClient : public DiagnosticClient { - Diagnostic &Diags; +class CaptureDiagnosticConsumer : public DiagnosticConsumer { + DiagnosticsEngine &Diags; CapturedDiagList &CapturedDiags; public: - CaptureDiagnosticClient(Diagnostic &diags, - CapturedDiagList &capturedDiags) + CaptureDiagnosticConsumer(DiagnosticsEngine &diags, + CapturedDiagList &capturedDiags) : Diags(diags), CapturedDiags(capturedDiags) { } - virtual void HandleDiagnostic(Diagnostic::Level level, - const DiagnosticInfo &Info) { + virtual void HandleDiagnostic(DiagnosticsEngine::Level level, + const Diagnostic &Info) { if (arcmt::isARCDiagnostic(Info.getID(), Diags) || - level >= Diagnostic::Error || level == Diagnostic::Note) { + level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) { CapturedDiags.push_back(StoredDiagnostic(level, Info)); return; } @@ -108,11 +107,17 @@ public: // Non-ARC warnings are ignored. Diags.setLastDiagnosticIgnored(); } + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + // Just drop any diagnostics that come from cloned consumers; they'll + // have different source managers anyway. + return new IgnoringDiagConsumer(); + } }; } // end anonymous namespace -static inline llvm::StringRef SimulatorVersionDefineName() { +static inline StringRef SimulatorVersionDefineName() { return "__IPHONE_OS_VERSION_MIN_REQUIRED="; } @@ -121,11 +126,11 @@ static inline llvm::StringRef SimulatorVersionDefineName() { // and return the grouped values as integers, e.g: // __IPHONE_OS_VERSION_MIN_REQUIRED=40201 // will return Major=4, Minor=2, Micro=1. -static bool GetVersionFromSimulatorDefine(llvm::StringRef define, +static bool GetVersionFromSimulatorDefine(StringRef define, unsigned &Major, unsigned &Minor, unsigned &Micro) { assert(define.startswith(SimulatorVersionDefineName())); - llvm::StringRef name, version; + StringRef name, version; llvm::tie(name, version) = define.split('='); if (version.empty()) return false; @@ -154,7 +159,7 @@ static bool HasARCRuntime(CompilerInvocation &origCI) { continue; if (!define.startswith(SimulatorVersionDefineName())) continue; - unsigned Major, Minor, Micro; + unsigned Major = 0, Minor = 0, Micro = 0; if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) && Major < 10 && Minor < 100 && Micro < 100) return Major >= 5; @@ -177,7 +182,8 @@ static bool HasARCRuntime(CompilerInvocation &origCI) { return false; } -CompilerInvocation *createInvocationForMigration(CompilerInvocation &origCI) { +static CompilerInvocation * +createInvocationForMigration(CompilerInvocation &origCI) { llvm::OwningPtr<CompilerInvocation> CInvok; CInvok.reset(new CompilerInvocation(origCI)); CInvok->getPreprocessorOpts().ImplicitPCHInclude = std::string(); @@ -194,13 +200,29 @@ CompilerInvocation *createInvocationForMigration(CompilerInvocation &origCI) { return CInvok.take(); } +static void emitPremigrationErrors(const CapturedDiagList &arcDiags, + const DiagnosticOptions &diagOpts, + Preprocessor &PP) { + TextDiagnosticPrinter printer(llvm::errs(), diagOpts); + llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, &printer, /*ShouldOwnClient=*/false)); + Diags->setSourceManager(&PP.getSourceManager()); + + printer.BeginSourceFile(PP.getLangOptions(), &PP); + arcDiags.reportDiagnostics(*Diags); + printer.EndSourceFile(); +} + //===----------------------------------------------------------------------===// // checkForManualIssues. //===----------------------------------------------------------------------===// bool arcmt::checkForManualIssues(CompilerInvocation &origCI, - llvm::StringRef Filename, InputKind Kind, - DiagnosticClient *DiagClient) { + StringRef Filename, InputKind Kind, + DiagnosticConsumer *DiagClient, + bool emitPremigrationARCErrors, + StringRef plistOut) { if (!origCI.getLangOpts().ObjC1) return false; @@ -216,11 +238,11 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, assert(DiagClient); llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags( - new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); // Filter of all diagnostics. - CaptureDiagnosticClient errRec(*Diags, capturedDiags); + CaptureDiagnosticConsumer errRec(*Diags, capturedDiags); Diags->setClient(&errRec, /*ShouldOwnClient=*/false); llvm::OwningPtr<ASTUnit> Unit( @@ -241,9 +263,21 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, return true; } + if (emitPremigrationARCErrors) + emitPremigrationErrors(capturedDiags, origCI.getDiagnosticOpts(), + Unit->getPreprocessor()); + if (!plistOut.empty()) { + SmallVector<StoredDiagnostic, 8> arcDiags; + for (CapturedDiagList::iterator + I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I) + arcDiags.push_back(*I); + writeARCDiagsToPlist(plistOut, arcDiags, + Ctx.getSourceManager(), Ctx.getLangOptions()); + } + // After parsing of source files ended, we want to reuse the // diagnostics objects to emit further diagnostics. - // We call BeginSourceFile because DiagnosticClient requires that + // We call BeginSourceFile because DiagnosticConsumer requires that // diagnostics with source range information are emitted only in between // BeginSourceFile() and EndSourceFile(). DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); @@ -266,7 +300,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, // to remove it so that we don't get errors from normal compilation. origCI.getLangOpts().ObjCAutoRefCount = false; - return capturedDiags.hasErrors(); + return capturedDiags.hasErrors() || testAct.hasReportedErrors(); } //===----------------------------------------------------------------------===// @@ -274,15 +308,18 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, //===----------------------------------------------------------------------===// static bool applyTransforms(CompilerInvocation &origCI, - llvm::StringRef Filename, InputKind Kind, - DiagnosticClient *DiagClient, - llvm::StringRef outputDir) { + StringRef Filename, InputKind Kind, + DiagnosticConsumer *DiagClient, + StringRef outputDir, + bool emitPremigrationARCErrors, + StringRef plistOut) { if (!origCI.getLangOpts().ObjC1) return false; // Make sure checking is successful first. CompilerInvocation CInvokForCheck(origCI); - if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient)) + if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient, + emitPremigrationARCErrors, plistOut)) return true; CompilerInvocation CInvok(origCI); @@ -300,8 +337,8 @@ static bool applyTransforms(CompilerInvocation &origCI, } llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags( - new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); if (outputDir.empty()) { origCI.getLangOpts().ObjCAutoRefCount = true; @@ -315,28 +352,32 @@ static bool applyTransforms(CompilerInvocation &origCI, } bool arcmt::applyTransformations(CompilerInvocation &origCI, - llvm::StringRef Filename, InputKind Kind, - DiagnosticClient *DiagClient) { - return applyTransforms(origCI, Filename, Kind, DiagClient, llvm::StringRef()); + StringRef Filename, InputKind Kind, + DiagnosticConsumer *DiagClient) { + return applyTransforms(origCI, Filename, Kind, DiagClient, + StringRef(), false, StringRef()); } bool arcmt::migrateWithTemporaryFiles(CompilerInvocation &origCI, - llvm::StringRef Filename, InputKind Kind, - DiagnosticClient *DiagClient, - llvm::StringRef outputDir) { + StringRef Filename, InputKind Kind, + DiagnosticConsumer *DiagClient, + StringRef outputDir, + bool emitPremigrationARCErrors, + StringRef plistOut) { assert(!outputDir.empty() && "Expected output directory path"); - return applyTransforms(origCI, Filename, Kind, DiagClient, outputDir); + return applyTransforms(origCI, Filename, Kind, DiagClient, + outputDir, emitPremigrationARCErrors, plistOut); } bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > & remap, - llvm::StringRef outputDir, - DiagnosticClient *DiagClient) { + StringRef outputDir, + DiagnosticConsumer *DiagClient) { assert(!outputDir.empty()); llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags( - new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); FileRemapper remapper; bool err = remapper.initFromDisk(outputDir, *Diags, @@ -364,7 +405,8 @@ public: ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs) : ARCMTMacroLocs(ARCMTMacroLocs) { } - virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo *MI) { + virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo *MI, + SourceRange Range) { if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); } @@ -378,7 +420,7 @@ public: : ARCMTMacroLocs(ARCMTMacroLocs) { } virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { CI.getPreprocessor().addPPCallbacks( new ARCMTMacroTrackerPPCallbacks(ARCMTMacroLocs)); return new ASTConsumer(); @@ -402,7 +444,7 @@ public: Listener->finish(); } - virtual void insert(SourceLocation loc, llvm::StringRef text) { + virtual void insert(SourceLocation loc, StringRef text) { bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true, /*indentNewLines=*/true); if (!err && Listener) @@ -432,13 +474,13 @@ public: MigrationProcess::RewriteListener::~RewriteListener() { } MigrationProcess::MigrationProcess(const CompilerInvocation &CI, - DiagnosticClient *diagClient, - llvm::StringRef outputDir) + DiagnosticConsumer *diagClient, + StringRef outputDir) : OrigCI(CI), DiagClient(diagClient) { if (!outputDir.empty()) { llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags( - new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true); } } @@ -456,11 +498,11 @@ bool MigrationProcess::applyTransform(TransformFn trans, assert(DiagClient); llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags( - new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); // Filter of all diagnostics. - CaptureDiagnosticClient errRec(*Diags, capturedDiags); + CaptureDiagnosticConsumer errRec(*Diags, capturedDiags); Diags->setClient(&errRec, /*ShouldOwnClient=*/false); llvm::OwningPtr<ARCMTMacroTrackerAction> ASTAction; @@ -488,7 +530,7 @@ bool MigrationProcess::applyTransform(TransformFn trans, // After parsing of source files ended, we want to reuse the // diagnostics objects to emit further diagnostics. - // We call BeginSourceFile because DiagnosticClient requires that + // We call BeginSourceFile because DiagnosticConsumer requires that // diagnostics with source range information are emitted only in between // BeginSourceFile() and EndSourceFile(). DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); @@ -522,7 +564,7 @@ bool MigrationProcess::applyTransform(TransformFn trans, buf.write(vecOS); vecOS.flush(); llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( - llvm::StringRef(newText.data(), newText.size()), newFname); + StringRef(newText.data(), newText.size()), newFname); llvm::SmallString<64> filePath(file->getName()); Unit->getFileManager().FixupRelativePath(filePath); Remapper.remap(filePath.str(), memBuf); @@ -535,7 +577,7 @@ bool MigrationProcess::applyTransform(TransformFn trans, // isARCDiagnostic. //===----------------------------------------------------------------------===// -bool arcmt::isARCDiagnostic(unsigned diagID, Diagnostic &Diag) { +bool arcmt::isARCDiagnostic(unsigned diagID, DiagnosticsEngine &Diag) { return Diag.getDiagnosticIDs()->getCategoryNumberForDiag(diagID) == diag::DiagCat_Automatic_Reference_Counting_Issue; } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMTActions.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMTActions.cpp index 345c745..dea867a 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMTActions.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMTActions.cpp @@ -38,16 +38,26 @@ ModifyAction::ModifyAction(FrontendAction *WrappedAction) : WrapperFrontendAction(WrappedAction) {} bool MigrateAction::BeginInvocation(CompilerInstance &CI) { - return !arcmt::migrateWithTemporaryFiles(CI.getInvocation(), + if (arcmt::migrateWithTemporaryFiles(CI.getInvocation(), getCurrentFile(), getCurrentFileKind(), CI.getDiagnostics().getClient(), - MigrateDir); + MigrateDir, + EmitPremigrationARCErros, + PlistOut)) + return false; // errors, stop the action. + + // We only want to see diagnostics emitted by migrateWithTemporaryFiles. + CI.getDiagnostics().setIgnoreAllWarnings(true); + return true; } MigrateAction::MigrateAction(FrontendAction *WrappedAction, - llvm::StringRef migrateDir) - : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir) { + StringRef migrateDir, + StringRef plistOut, + bool emitPremigrationARCErrors) + : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir), + PlistOut(plistOut), EmitPremigrationARCErros(emitPremigrationARCErrors) { if (MigrateDir.empty()) MigrateDir = "."; // user current directory if none is given. } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/CMakeLists.txt b/contrib/llvm/tools/clang/lib/ARCMigrate/CMakeLists.txt deleted file mode 100644 index 5f2711e..0000000 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -set(LLVM_USED_LIBS clangBasic clangAST clangParse clangFrontend clangRewrite) - -add_clang_library(clangARCMigrate - ARCMT.cpp - ARCMTActions.cpp - FileRemapper.cpp - TransARCAssign.cpp - TransAutoreleasePool.cpp - TransBlockObjCVariable.cpp - TransEmptyStatementsAndDealloc.cpp - TransformActions.cpp - Transforms.cpp - TransProperties.cpp - TransRetainReleaseDealloc.cpp - TransUnbridgedCasts.cpp - TransUnusedInitDelegate.cpp - TransZeroOutPropsInDealloc.cpp - ) - -add_dependencies(clangARCMigrate - ClangAttrClasses - ClangAttrList - ClangDeclNodes - ClangStmtNodes) diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/FileRemapper.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/FileRemapper.cpp index db26c29..c6e6ce4 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/FileRemapper.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/FileRemapper.cpp @@ -27,7 +27,7 @@ FileRemapper::~FileRemapper() { clear(); } -void FileRemapper::clear(llvm::StringRef outputDir) { +void FileRemapper::clear(StringRef outputDir) { for (MappingsTy::iterator I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) resetTarget(I->second); @@ -40,7 +40,7 @@ void FileRemapper::clear(llvm::StringRef outputDir) { } } -std::string FileRemapper::getRemapInfoFile(llvm::StringRef outputDir) { +std::string FileRemapper::getRemapInfoFile(StringRef outputDir) { assert(!outputDir.empty()); llvm::sys::Path dir(outputDir); llvm::sys::Path infoFile = dir; @@ -48,7 +48,7 @@ std::string FileRemapper::getRemapInfoFile(llvm::StringRef outputDir) { return infoFile.str(); } -bool FileRemapper::initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag, +bool FileRemapper::initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag, bool ignoreIfFilesChanged) { assert(FromToMappings.empty() && "initFromDisk should be called before any remap calls"); @@ -59,38 +59,38 @@ bool FileRemapper::initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag, return false; std::vector<std::pair<const FileEntry *, const FileEntry *> > pairs; - - std::ifstream fin(infoFile.c_str()); - if (!fin.good()) - return report(std::string("Error opening file: ") + infoFile, Diag); - - while (true) { - std::string fromFilename, toFilename; - uint64_t timeModified; - - fin >> fromFilename >> timeModified >> toFilename; - if (fin.eof()) - break; - if (!fin.good()) - return report(std::string("Error in format of file: ") + infoFile, Diag); - + + llvm::OwningPtr<llvm::MemoryBuffer> fileBuf; + if (llvm::error_code ec = llvm::MemoryBuffer::getFile(infoFile.c_str(), + fileBuf)) + return report("Error opening file: " + infoFile, Diag); + + SmallVector<StringRef, 64> lines; + fileBuf->getBuffer().split(lines, "\n"); + + for (unsigned idx = 0; idx+3 <= lines.size(); idx += 3) { + StringRef fromFilename = lines[idx]; + unsigned long long timeModified; + lines[idx+1].getAsInteger(10, timeModified); + StringRef toFilename = lines[idx+2]; + const FileEntry *origFE = FileMgr->getFile(fromFilename); if (!origFE) { if (ignoreIfFilesChanged) continue; - return report(std::string("File does not exist: ") + fromFilename, Diag); + return report("File does not exist: " + fromFilename, Diag); } const FileEntry *newFE = FileMgr->getFile(toFilename); if (!newFE) { if (ignoreIfFilesChanged) continue; - return report(std::string("File does not exist: ") + toFilename, Diag); + return report("File does not exist: " + toFilename, Diag); } if ((uint64_t)origFE->getModificationTime() != timeModified) { if (ignoreIfFilesChanged) continue; - return report(std::string("File was modified: ") + fromFilename, Diag); + return report("File was modified: " + fromFilename, Diag); } pairs.push_back(std::make_pair(origFE, newFE)); @@ -102,13 +102,12 @@ bool FileRemapper::initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag, return false; } -bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) { +bool FileRemapper::flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag) { using namespace llvm::sys; bool existed; if (fs::create_directory(outputDir, existed) != llvm::errc::success) - return report(std::string("Could not create directory: ") + outputDir.str(), - Diag); + return report("Could not create directory: " + outputDir, Diag); std::string errMsg; std::string infoFile = getRemapInfoFile(outputDir); @@ -121,13 +120,13 @@ bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) { I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) { const FileEntry *origFE = I->first; - llvm::SmallString<200> origPath = llvm::StringRef(origFE->getName()); + llvm::SmallString<200> origPath = StringRef(origFE->getName()); fs::make_absolute(origPath); infoOut << origPath << '\n'; infoOut << (uint64_t)origFE->getModificationTime() << '\n'; if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) { - llvm::SmallString<200> newPath = llvm::StringRef(FE->getName()); + llvm::SmallString<200> newPath = StringRef(FE->getName()); fs::make_absolute(newPath); infoOut << newPath << '\n'; } else { @@ -138,8 +137,7 @@ bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) { tempPath += path::extension(origFE->getName()); int fd; if (fs::unique_file(tempPath.str(), fd, tempPath) != llvm::errc::success) - return report(std::string("Could not create file: ") + tempPath.c_str(), - Diag); + return report("Could not create file: " + tempPath.str(), Diag); llvm::raw_fd_ostream newOut(fd, /*shouldClose=*/true); llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>(); @@ -156,8 +154,8 @@ bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) { return false; } -bool FileRemapper::overwriteOriginal(Diagnostic &Diag, - llvm::StringRef outputDir) { +bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag, + StringRef outputDir) { using namespace llvm::sys; for (MappingsTy::iterator @@ -165,20 +163,15 @@ bool FileRemapper::overwriteOriginal(Diagnostic &Diag, const FileEntry *origFE = I->first; if (const FileEntry *newFE = I->second.dyn_cast<const FileEntry *>()) { if (fs::copy_file(newFE->getName(), origFE->getName(), - fs::copy_option::overwrite_if_exists) != llvm::errc::success) { - std::string err = "Could not copy file '"; - llvm::raw_string_ostream os(err); - os << "Could not copy file '" << newFE->getName() << "' to file '" - << origFE->getName() << "'"; - os.flush(); - return report(err, Diag); - } + fs::copy_option::overwrite_if_exists) != llvm::errc::success) + return report(StringRef("Could not copy file '") + newFE->getName() + + "' to file '" + origFE->getName() + "'", Diag); } else { bool fileExists = false; fs::exists(origFE->getName(), fileExists); if (!fileExists) - return report(std::string("File does not exist: ") + origFE->getName(), + return report(StringRef("File does not exist: ") + origFE->getName(), Diag); std::string errMsg; @@ -229,11 +222,11 @@ void FileRemapper::transferMappingsAndClear(CompilerInvocation &CI) { clear(); } -void FileRemapper::remap(llvm::StringRef filePath, llvm::MemoryBuffer *memBuf) { +void FileRemapper::remap(StringRef filePath, llvm::MemoryBuffer *memBuf) { remap(getOriginalFile(filePath), memBuf); } -void FileRemapper::remap(llvm::StringRef filePath, llvm::StringRef newPath) { +void FileRemapper::remap(StringRef filePath, StringRef newPath) { const FileEntry *file = getOriginalFile(filePath); const FileEntry *newfile = FileMgr->getFile(newPath); remap(file, newfile); @@ -254,7 +247,7 @@ void FileRemapper::remap(const FileEntry *file, const FileEntry *newfile) { ToFromMappings[newfile] = file; } -const FileEntry *FileRemapper::getOriginalFile(llvm::StringRef filePath) { +const FileEntry *FileRemapper::getOriginalFile(StringRef filePath) { const FileEntry *file = FileMgr->getFile(filePath); // If we are updating a file that overriden an original file, // actually update the original file. @@ -283,9 +276,10 @@ void FileRemapper::resetTarget(Target &targ) { } } -bool FileRemapper::report(const std::string &err, Diagnostic &Diag) { +bool FileRemapper::report(const Twine &err, DiagnosticsEngine &Diag) { + llvm::SmallString<128> buf; unsigned ID = Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error, - err); + err.toStringRef(buf)); Diag.Report(ID); return true; } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/Internals.h b/contrib/llvm/tools/clang/lib/ARCMigrate/Internals.h index 4f9b138..46f3bb6 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/Internals.h +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/Internals.h @@ -26,21 +26,30 @@ class CapturedDiagList { public: void push_back(const StoredDiagnostic &diag) { List.push_back(diag); } - bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range); - bool hasDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range) const; + bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); + bool hasDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) const; - void reportDiagnostics(Diagnostic &diags) const; + void reportDiagnostics(DiagnosticsEngine &diags) const; bool hasErrors() const; + + typedef ListTy::const_iterator iterator; + iterator begin() const { return List.begin(); } + iterator end() const { return List.end(); } }; +void writeARCDiagsToPlist(const std::string &outPath, + ArrayRef<StoredDiagnostic> diags, + SourceManager &SM, const LangOptions &LangOpts); + class TransformActions { - Diagnostic &Diags; + DiagnosticsEngine &Diags; CapturedDiagList &CapturedDiags; + bool ReportedErrors; void *Impl; // TransformActionsImpl. public: - TransformActions(Diagnostic &diag, CapturedDiagList &capturedDiags, + TransformActions(DiagnosticsEngine &diag, CapturedDiagList &capturedDiags, ASTContext &ctx, Preprocessor &PP); ~TransformActions(); @@ -48,21 +57,21 @@ public: bool commitTransaction(); void abortTransaction(); - void insert(SourceLocation loc, llvm::StringRef text); - void insertAfterToken(SourceLocation loc, llvm::StringRef text); + void insert(SourceLocation loc, StringRef text); + void insertAfterToken(SourceLocation loc, StringRef text); void remove(SourceRange range); void removeStmt(Stmt *S); - void replace(SourceRange range, llvm::StringRef text); + void replace(SourceRange range, StringRef text); void replace(SourceRange range, SourceRange replacementRange); - void replaceStmt(Stmt *S, llvm::StringRef text); - void replaceText(SourceLocation loc, llvm::StringRef text, - llvm::StringRef replacementText); + void replaceStmt(Stmt *S, StringRef text); + void replaceText(SourceLocation loc, StringRef text, + StringRef replacementText); void increaseIndentation(SourceRange range, SourceLocation parentIndent); - bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range); + bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); bool clearAllDiagnostics(SourceRange range) { - return clearDiagnostic(llvm::ArrayRef<unsigned>(), range); + return clearDiagnostic(ArrayRef<unsigned>(), range); } bool clearDiagnostic(unsigned ID1, unsigned ID2, SourceRange range) { unsigned IDs[] = { ID1, ID2 }; @@ -83,16 +92,18 @@ public: return CapturedDiags.hasDiagnostic(IDs, range); } - void reportError(llvm::StringRef error, SourceLocation loc, + void reportError(StringRef error, SourceLocation loc, SourceRange range = SourceRange()); - void reportNote(llvm::StringRef note, SourceLocation loc, + void reportNote(StringRef note, SourceLocation loc, SourceRange range = SourceRange()); + bool hasReportedErrors() const { return ReportedErrors; } + class RewriteReceiver { public: virtual ~RewriteReceiver(); - virtual void insert(SourceLocation loc, llvm::StringRef text) = 0; + virtual void insert(SourceLocation loc, StringRef text) = 0; virtual void remove(CharSourceRange range) = 0; virtual void increaseIndentation(CharSourceRange range, SourceLocation parentIndent) = 0; @@ -135,9 +146,9 @@ public: : Ctx(Ctx), SemaRef(sema), TA(TA), ARCMTMacroLocs(ARCMTMacroLocs) { } }; -bool isARCDiagnostic(unsigned diagID, Diagnostic &Diag); +bool isARCDiagnostic(unsigned diagID, DiagnosticsEngine &Diag); -static inline llvm::StringRef getARCMTMacroName() { +static inline StringRef getARCMTMacroName() { return "__IMPL_ARCMT_REMOVED_EXPR__"; } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/Makefile b/contrib/llvm/tools/clang/lib/ARCMigrate/Makefile deleted file mode 100644 index 5232c5e..0000000 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- clang/lib/ARCMigrate/Makefile --------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements code transformation to ARC mode. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../.. -LIBRARYNAME := clangARCMigrate - -include $(CLANG_LEVEL)/Makefile - diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/PlistReporter.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/PlistReporter.cpp new file mode 100644 index 0000000..d1bc90f --- /dev/null +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/PlistReporter.cpp @@ -0,0 +1,195 @@ +//===--- PlistReporter.cpp - ARC Migrate Tool Plist Reporter ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Internals.h" +#include "clang/Lex/Lexer.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +using namespace clang; +using namespace arcmt; + +// FIXME: This duplicates significant functionality from PlistDiagnostics.cpp, +// it would be jolly good if there was a reusable PlistWriter or something. + +typedef llvm::DenseMap<FileID, unsigned> FIDMap; + +static void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V, + const SourceManager &SM, SourceLocation L) { + + FileID FID = SM.getFileID(SM.getExpansionLoc(L)); + FIDMap::iterator I = FIDs.find(FID); + if (I != FIDs.end()) return; + FIDs[FID] = V.size(); + V.push_back(FID); +} + +static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM, + SourceLocation L) { + FileID FID = SM.getFileID(SM.getExpansionLoc(L)); + FIDMap::const_iterator I = FIDs.find(FID); + assert(I != FIDs.end()); + return I->second; +} + +static raw_ostream& Indent(raw_ostream& o, const unsigned indent) { + for (unsigned i = 0; i < indent; ++i) o << ' '; + return o; +} + +static void EmitLocation(raw_ostream& o, const SourceManager &SM, + const LangOptions &LangOpts, + SourceLocation L, const FIDMap &FM, + unsigned indent, bool extend = false) { + + FullSourceLoc Loc(SM.getExpansionLoc(L), const_cast<SourceManager&>(SM)); + + // Add in the length of the token, so that we cover multi-char tokens. + unsigned offset = + extend ? Lexer::MeasureTokenLength(Loc, SM, LangOpts) - 1 : 0; + + Indent(o, indent) << "<dict>\n"; + Indent(o, indent) << " <key>line</key><integer>" + << Loc.getExpansionLineNumber() << "</integer>\n"; + Indent(o, indent) << " <key>col</key><integer>" + << Loc.getExpansionColumnNumber() + offset << "</integer>\n"; + Indent(o, indent) << " <key>file</key><integer>" + << GetFID(FM, SM, Loc) << "</integer>\n"; + Indent(o, indent) << "</dict>\n"; +} + +static void EmitRange(raw_ostream& o, const SourceManager &SM, + const LangOptions &LangOpts, + CharSourceRange R, const FIDMap &FM, + unsigned indent) { + Indent(o, indent) << "<array>\n"; + EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1); + EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, R.isTokenRange()); + Indent(o, indent) << "</array>\n"; +} + +static raw_ostream& EmitString(raw_ostream& o, + StringRef s) { + o << "<string>"; + for (StringRef::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) { + char c = *I; + switch (c) { + default: o << c; break; + case '&': o << "&"; break; + case '<': o << "<"; break; + case '>': o << ">"; break; + case '\'': o << "'"; break; + case '\"': o << """; break; + } + } + o << "</string>"; + return o; +} + +void arcmt::writeARCDiagsToPlist(const std::string &outPath, + ArrayRef<StoredDiagnostic> diags, + SourceManager &SM, + const LangOptions &LangOpts) { + DiagnosticIDs DiagIDs; + + // Build up a set of FIDs that we use by scanning the locations and + // ranges of the diagnostics. + FIDMap FM; + SmallVector<FileID, 10> Fids; + + for (ArrayRef<StoredDiagnostic>::iterator + I = diags.begin(), E = diags.end(); I != E; ++I) { + const StoredDiagnostic &D = *I; + + AddFID(FM, Fids, SM, D.getLocation()); + + for (StoredDiagnostic::range_iterator + RI = D.range_begin(), RE = D.range_end(); RI != RE; ++RI) { + AddFID(FM, Fids, SM, RI->getBegin()); + AddFID(FM, Fids, SM, RI->getEnd()); + } + } + + std::string errMsg; + llvm::raw_fd_ostream o(outPath.c_str(), errMsg); + if (!errMsg.empty()) { + llvm::errs() << "error: could not create file: " << outPath << '\n'; + return; + } + + // Write the plist header. + o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" " + "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" + "<plist version=\"1.0\">\n"; + + // Write the root object: a <dict> containing... + // - "files", an <array> mapping from FIDs to file names + // - "diagnostics", an <array> containing the diagnostics + o << "<dict>\n" + " <key>files</key>\n" + " <array>\n"; + + for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end(); + I!=E; ++I) { + o << " "; + EmitString(o, SM.getFileEntryForID(*I)->getName()) << '\n'; + } + + o << " </array>\n" + " <key>diagnostics</key>\n" + " <array>\n"; + + for (ArrayRef<StoredDiagnostic>::iterator + DI = diags.begin(), DE = diags.end(); DI != DE; ++DI) { + + const StoredDiagnostic &D = *DI; + + if (D.getLevel() == DiagnosticsEngine::Ignored) + continue; + + o << " <dict>\n"; + + // Output the diagnostic. + o << " <key>description</key>"; + EmitString(o, D.getMessage()) << '\n'; + o << " <key>category</key>"; + EmitString(o, DiagIDs.getCategoryNameFromID( + DiagIDs.getCategoryNumberForDiag(D.getID()))) << '\n'; + o << " <key>type</key>"; + if (D.getLevel() >= DiagnosticsEngine::Error) + EmitString(o, "error") << '\n'; + else if (D.getLevel() == DiagnosticsEngine::Warning) + EmitString(o, "warning") << '\n'; + else + EmitString(o, "note") << '\n'; + + // Output the location of the bug. + o << " <key>location</key>\n"; + EmitLocation(o, SM, LangOpts, D.getLocation(), FM, 2); + + // Output the ranges (if any). + StoredDiagnostic::range_iterator RI = D.range_begin(), RE = D.range_end(); + + if (RI != RE) { + o << " <key>ranges</key>\n"; + o << " <array>\n"; + for (; RI != RE; ++RI) + EmitRange(o, SM, LangOpts, *RI, FM, 4); + o << " </array>\n"; + } + + // Close up the entry. + o << " </dict>\n"; + } + + o << " </array>\n"; + + // Finish. + o << "</dict>\n</plist>"; +} diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransAPIUses.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransAPIUses.cpp new file mode 100644 index 0000000..aaa82d8 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransAPIUses.cpp @@ -0,0 +1,109 @@ +//===--- TransAPIUses.cpp - Tranformations to ARC mode --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// checkAPIUses: +// +// Emits error/fix with some API uses that are obsolete or not safe in ARC mode: +// +// - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe +// with __unsafe_unretained objects. +// - Calling -zone gets replaced with 'nil'. +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/Sema/SemaDiagnostic.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; + +namespace { + +class APIChecker : public RecursiveASTVisitor<APIChecker> { + MigrationPass &Pass; + + Selector getReturnValueSel, setReturnValueSel; + Selector getArgumentSel, setArgumentSel; + + Selector zoneSel; +public: + APIChecker(MigrationPass &pass) : Pass(pass) { + SelectorTable &sels = Pass.Ctx.Selectors; + IdentifierTable &ids = Pass.Ctx.Idents; + getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue")); + setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue")); + + IdentifierInfo *selIds[2]; + selIds[0] = &ids.get("getArgument"); + selIds[1] = &ids.get("atIndex"); + getArgumentSel = sels.getSelector(2, selIds); + selIds[0] = &ids.get("setArgument"); + setArgumentSel = sels.getSelector(2, selIds); + + zoneSel = sels.getNullarySelector(&ids.get("zone")); + } + + bool VisitObjCMessageExpr(ObjCMessageExpr *E) { + // NSInvocation. + if (E->isInstanceMessage() && + E->getReceiverInterface() && + E->getReceiverInterface()->getName() == "NSInvocation") { + StringRef selName; + if (E->getSelector() == getReturnValueSel) + selName = "getReturnValue"; + else if (E->getSelector() == setReturnValueSel) + selName = "setReturnValue"; + else if (E->getSelector() == getArgumentSel) + selName = "getArgument"; + else if (E->getSelector() == setArgumentSel) + selName = "setArgument"; + + if (selName.empty()) + return true; + + Expr *parm = E->getArg(0)->IgnoreParenCasts(); + QualType pointee = parm->getType()->getPointeeType(); + if (pointee.isNull()) + return true; + + if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) { + std::string err = "NSInvocation's "; + err += selName; + err += " is not safe to be used with an object with ownership other " + "than __unsafe_unretained"; + Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange()); + } + return true; + } + + // -zone. + if (E->isInstanceMessage() && + E->getInstanceReceiver() && + E->getSelector() == zoneSel && + Pass.TA.hasDiagnostic(diag::err_unavailable, + diag::err_unavailable_message, + E->getInstanceReceiver()->getExprLoc())) { + // Calling -zone is meaningless in ARC, change it to nil. + Transaction Trans(Pass.TA); + Pass.TA.clearDiagnostic(diag::err_unavailable, + diag::err_unavailable_message, + E->getInstanceReceiver()->getExprLoc()); + Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx)); + } + return true; + } +}; + +} // anonymous namespace + +void trans::checkAPIUses(MigrationPass &pass) { + APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +} diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransARCAssign.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransARCAssign.cpp index 8c00df5..1f10196 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransARCAssign.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransARCAssign.cpp @@ -28,7 +28,6 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransAutoreleasePool.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransAutoreleasePool.cpp index 5b84854..08561f9 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransAutoreleasePool.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransAutoreleasePool.cpp @@ -36,16 +36,15 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { class ReleaseCollector : public RecursiveASTVisitor<ReleaseCollector> { Decl *Dcl; - llvm::SmallVectorImpl<ObjCMessageExpr *> &Releases; + SmallVectorImpl<ObjCMessageExpr *> &Releases; public: - ReleaseCollector(Decl *D, llvm::SmallVectorImpl<ObjCMessageExpr *> &releases) + ReleaseCollector(Decl *D, SmallVectorImpl<ObjCMessageExpr *> &releases) : Dcl(D), Releases(releases) { } bool VisitObjCMessageExpr(ObjCMessageExpr *E) { @@ -82,7 +81,7 @@ public: } ~AutoreleasePoolRewriter() { - llvm::SmallVector<VarDecl *, 8> VarsToHandle; + SmallVector<VarDecl *, 8> VarsToHandle; for (std::map<VarDecl *, PoolVarInfo>::iterator I = PoolVars.begin(), E = PoolVars.end(); I != E; ++I) { @@ -92,7 +91,7 @@ public: // Check that we can handle/rewrite all references of the pool. clearRefsIn(info.Dcl, info.Refs); - for (llvm::SmallVectorImpl<PoolScope>::iterator + for (SmallVectorImpl<PoolScope>::iterator scpI = info.Scopes.begin(), scpE = info.Scopes.end(); scpI != scpE; ++scpI) { PoolScope &scope = *scpI; @@ -116,7 +115,7 @@ public: Pass.TA.removeStmt(info.Dcl); // Add "@autoreleasepool { }" - for (llvm::SmallVectorImpl<PoolScope>::iterator + for (SmallVectorImpl<PoolScope>::iterator scpI = info.Scopes.begin(), scpE = info.Scopes.end(); scpI != scpE; ++scpI) { PoolScope &scope = *scpI; @@ -147,11 +146,11 @@ public: } // Remove rest of pool var references. - for (llvm::SmallVectorImpl<PoolScope>::iterator + for (SmallVectorImpl<PoolScope>::iterator scpI = info.Scopes.begin(), scpE = info.Scopes.end(); scpI != scpE; ++scpI) { PoolScope &scope = *scpI; - for (llvm::SmallVectorImpl<ObjCMessageExpr *>::iterator + for (SmallVectorImpl<ObjCMessageExpr *>::iterator relI = scope.Releases.begin(), relE = scope.Releases.end(); relI != relE; ++relI) { clearUnavailableDiags(*relI); @@ -162,7 +161,7 @@ public: } bool VisitCompoundStmt(CompoundStmt *S) { - llvm::SmallVector<PoolScope, 4> Scopes; + SmallVector<PoolScope, 4> Scopes; for (Stmt::child_iterator I = S->body_begin(), E = S->body_end(); I != E; ++I) { @@ -228,7 +227,7 @@ private: Stmt::child_iterator Begin; Stmt::child_iterator End; bool IsFollowedBySimpleReturnStmt; - llvm::SmallVector<ObjCMessageExpr *, 4> Releases; + SmallVector<ObjCMessageExpr *, 4> Releases; PoolScope() : PoolVar(0), CompoundParent(0), Begin(), End(), IsFollowedBySimpleReturnStmt(false) { } @@ -287,6 +286,9 @@ private: } bool isInScope(SourceLocation loc) { + if (loc.isInvalid()) + return false; + SourceManager &SM = Ctx.getSourceManager(); if (SM.isBeforeInTranslationUnit(loc, ScopeRange.getBegin())) return false; @@ -420,7 +422,7 @@ private: struct PoolVarInfo { DeclStmt *Dcl; ExprSet Refs; - llvm::SmallVector<PoolScope, 2> Scopes; + SmallVector<PoolScope, 2> Scopes; PoolVarInfo() : Dcl(0) { } }; diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp index 0e342b7..48c0ca9 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp @@ -32,7 +32,6 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { @@ -75,7 +74,7 @@ public: RootBlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { } bool VisitBlockDecl(BlockDecl *block) { - llvm::SmallVector<VarDecl *, 4> BlockVars; + SmallVector<VarDecl *, 4> BlockVars; for (BlockDecl::capture_iterator I = block->capture_begin(), E = block->capture_end(); I != E; ++I) { @@ -101,7 +100,7 @@ public: bool useWeak = canApplyWeak(Pass.Ctx, var->getType()); SourceManager &SM = Pass.Ctx.getSourceManager(); Transaction Trans(Pass.TA); - Pass.TA.replaceText(SM.getInstantiationLoc(attr->getLocation()), + Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()), "__block", useWeak ? "__weak" : "__unsafe_unretained"); } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp index d0bc332..3ad05e6 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp @@ -22,11 +22,53 @@ #include "Transforms.h" #include "Internals.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Basic/SourceManager.h" using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; + +static bool isEmptyARCMTMacroStatement(NullStmt *S, + std::vector<SourceLocation> &MacroLocs, + ASTContext &Ctx) { + if (!S->hasLeadingEmptyMacro()) + return false; + + SourceLocation SemiLoc = S->getSemiLoc(); + if (SemiLoc.isInvalid() || SemiLoc.isMacroID()) + return false; + + if (MacroLocs.empty()) + return false; + + SourceManager &SM = Ctx.getSourceManager(); + std::vector<SourceLocation>::iterator + I = std::upper_bound(MacroLocs.begin(), MacroLocs.end(), SemiLoc, + SourceManager::LocBeforeThanCompare(SM)); + --I; + SourceLocation + AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size()); + assert(AfterMacroLoc.isFileID()); + + if (AfterMacroLoc == SemiLoc) + return true; + + int RelOffs = 0; + if (!SM.isInSameSLocAddrSpace(AfterMacroLoc, SemiLoc, &RelOffs)) + return false; + if (RelOffs < 0) + return false; + + // We make the reasonable assumption that a semicolon after 100 characters + // means that it is not the next token after our macro. If this assumption + // fails it is not critical, we will just fail to clear out, e.g., an empty + // 'if'. + if (RelOffs - getARCMTMacroName().size() > 100) + return false; + + SourceLocation AfterMacroSemiLoc = findSemiAfterLocation(AfterMacroLoc, Ctx); + return AfterMacroSemiLoc == SemiLoc; +} namespace { @@ -34,14 +76,14 @@ namespace { /// transformations. class EmptyChecker : public StmtVisitor<EmptyChecker, bool> { ASTContext &Ctx; - llvm::DenseSet<unsigned> &MacroLocs; + std::vector<SourceLocation> &MacroLocs; public: - EmptyChecker(ASTContext &ctx, llvm::DenseSet<unsigned> ¯oLocs) + EmptyChecker(ASTContext &ctx, std::vector<SourceLocation> ¯oLocs) : Ctx(ctx), MacroLocs(macroLocs) { } bool VisitNullStmt(NullStmt *S) { - return isMacroLoc(S->getLeadingEmptyMacroLoc()); + return isEmptyARCMTMacroStatement(S, MacroLocs, Ctx); } bool VisitCompoundStmt(CompoundStmt *S) { if (S->body_empty()) @@ -103,23 +145,14 @@ public: return false; return Visit(S->getSubStmt()); } - -private: - bool isMacroLoc(SourceLocation loc) { - if (loc.isInvalid()) return false; - return MacroLocs.count(loc.getRawEncoding()); - } }; class EmptyStatementsRemover : public RecursiveASTVisitor<EmptyStatementsRemover> { MigrationPass &Pass; - llvm::DenseSet<unsigned> &MacroLocs; public: - EmptyStatementsRemover(MigrationPass &pass, - llvm::DenseSet<unsigned> ¯oLocs) - : Pass(pass), MacroLocs(macroLocs) { } + EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) { } bool TraverseStmtExpr(StmtExpr *E) { CompoundStmt *S = E->getSubStmt(); @@ -139,17 +172,12 @@ public: return true; } - bool isMacroLoc(SourceLocation loc) { - if (loc.isInvalid()) return false; - return MacroLocs.count(loc.getRawEncoding()); - } - ASTContext &getContext() { return Pass.Ctx; } private: void check(Stmt *S) { if (!S) return; - if (EmptyChecker(Pass.Ctx, MacroLocs).Visit(S)) { + if (EmptyChecker(Pass.Ctx, Pass.ARCMTMacroLocs).Visit(S)) { Transaction Trans(Pass.TA); Pass.TA.removeStmt(S); } @@ -158,8 +186,8 @@ private: } // anonymous namespace -static bool isBodyEmpty(CompoundStmt *body, - ASTContext &Ctx, llvm::DenseSet<unsigned> &MacroLocs) { +static bool isBodyEmpty(CompoundStmt *body, ASTContext &Ctx, + std::vector<SourceLocation> &MacroLocs) { for (CompoundStmt::body_iterator I = body->body_begin(), E = body->body_end(); I != E; ++I) if (!EmptyChecker(Ctx, MacroLocs).Visit(*I)) @@ -168,8 +196,7 @@ static bool isBodyEmpty(CompoundStmt *body, return true; } -static void removeDeallocMethod(MigrationPass &pass, - llvm::DenseSet<unsigned> &MacroLocs) { +static void removeDeallocMethod(MigrationPass &pass) { ASTContext &Ctx = pass.Ctx; TransformActions &TA = pass.TA; DeclContext *DC = Ctx.getTranslationUnitDecl(); @@ -184,7 +211,7 @@ static void removeDeallocMethod(MigrationPass &pass, ObjCMethodDecl *MD = *MI; if (MD->getMethodFamily() == OMF_dealloc) { if (MD->hasBody() && - isBodyEmpty(MD->getCompoundBody(), Ctx, MacroLocs)) { + isBodyEmpty(MD->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) { Transaction Trans(TA); TA.remove(MD->getSourceRange()); } @@ -195,14 +222,9 @@ static void removeDeallocMethod(MigrationPass &pass, } void trans::removeEmptyStatementsAndDealloc(MigrationPass &pass) { - llvm::DenseSet<unsigned> MacroLocs; - for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) - MacroLocs.insert(pass.ARCMTMacroLocs[i].getRawEncoding()); - - EmptyStatementsRemover(pass, MacroLocs) - .TraverseDecl(pass.Ctx.getTranslationUnitDecl()); + EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); - removeDeallocMethod(pass, MacroLocs); + removeDeallocMethod(pass); for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) { Transaction Trans(pass.TA); diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp index 872c95e..ca845b6 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp @@ -40,12 +40,12 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { class PropertiesRewriter { MigrationPass &Pass; + ObjCImplementationDecl *CurImplD; struct PropData { ObjCPropertyDecl *PropD; @@ -55,7 +55,7 @@ class PropertiesRewriter { PropData(ObjCPropertyDecl *propD) : PropD(propD), IvarD(0), ImplD(0) { } }; - typedef llvm::SmallVector<PropData, 2> PropsTy; + typedef SmallVector<PropData, 2> PropsTy; typedef std::map<unsigned, PropsTy> AtPropDeclsTy; AtPropDeclsTy AtProps; @@ -63,6 +63,7 @@ public: PropertiesRewriter(MigrationPass &pass) : Pass(pass) { } void doTransform(ObjCImplementationDecl *D) { + CurImplD = D; ObjCInterfaceDecl *iface = D->getClassInterface(); if (!iface) return; @@ -135,8 +136,16 @@ private: return; } - if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) + if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) { + if (hasIvarAssignedAPlusOneObject(props)) { + rewriteAttribute("assign", "strong", atLoc); + return; + } return rewriteAssign(props, atLoc); + } + + if (hasIvarAssignedAPlusOneObject(props)) + return maybeAddStrongAttr(props, atLoc); return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc); } @@ -163,15 +172,15 @@ private: void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props, SourceLocation atLoc) const { ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props); - if ((propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) && - hasNoBackingIvars(props)) - return; bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props)); - bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained", - atLoc); - if (!addedAttr) - canUseWeak = false; + if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) || + !hasAllIvarsBacked(props)) { + bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained", + atLoc); + if (!addedAttr) + canUseWeak = false; + } for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { if (isUserDeclared(I->IvarD)) @@ -187,7 +196,26 @@ private: } } - bool rewriteAttribute(llvm::StringRef fromAttr, llvm::StringRef toAttr, + void maybeAddStrongAttr(PropsTy &props, SourceLocation atLoc) const { + ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props); + + if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) || + !hasAllIvarsBacked(props)) { + addAttribute("strong", atLoc); + } + + for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { + if (I->ImplD) { + Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership, + I->ImplD->getLocation()); + Pass.TA.clearDiagnostic( + diag::err_arc_objc_property_default_assign_on_object, + I->ImplD->getLocation()); + } + } + } + + bool rewriteAttribute(StringRef fromAttr, StringRef toAttr, SourceLocation atLoc) const { if (atLoc.isMacroID()) return false; @@ -199,7 +227,7 @@ private: // Try to load the file buffer. bool invalidTemp = false; - llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); if (invalidTemp) return false; @@ -214,7 +242,7 @@ private: if (tok.isNot(tok::at)) return false; lexer.LexFromRawLexer(tok); if (tok.isNot(tok::raw_identifier)) return false; - if (llvm::StringRef(tok.getRawIdentifierData(), tok.getLength()) + if (StringRef(tok.getRawIdentifierData(), tok.getLength()) != "property") return false; lexer.LexFromRawLexer(tok); @@ -226,7 +254,7 @@ private: while (1) { if (tok.isNot(tok::raw_identifier)) return false; - llvm::StringRef ident(tok.getRawIdentifierData(), tok.getLength()); + StringRef ident(tok.getRawIdentifierData(), tok.getLength()); if (ident == fromAttr) { Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr); return true; @@ -243,7 +271,7 @@ private: return false; } - bool addAttribute(llvm::StringRef attr, SourceLocation atLoc) const { + bool addAttribute(StringRef attr, SourceLocation atLoc) const { if (atLoc.isMacroID()) return false; @@ -254,7 +282,7 @@ private: // Try to load the file buffer. bool invalidTemp = false; - llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); if (invalidTemp) return false; @@ -269,7 +297,7 @@ private: if (tok.isNot(tok::at)) return false; lexer.LexFromRawLexer(tok); if (tok.isNot(tok::raw_identifier)) return false; - if (llvm::StringRef(tok.getRawIdentifierData(), tok.getLength()) + if (StringRef(tok.getRawIdentifierData(), tok.getLength()) != "property") return false; lexer.LexFromRawLexer(tok); @@ -291,6 +319,45 @@ private: return true; } + class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> { + ObjCIvarDecl *Ivar; + public: + PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {} + + bool VisitBinAssign(BinaryOperator *E) { + Expr *lhs = E->getLHS()->IgnoreParenImpCasts(); + if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) { + if (RE->getDecl() != Ivar) + return true; + + if (ObjCMessageExpr * + ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts())) + if (ME->getMethodFamily() == OMF_retain) + return false; + + ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS()); + while (implCE && implCE->getCastKind() == CK_BitCast) + implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr()); + + if (implCE && implCE->getCastKind() == CK_ARCConsumeObject) + return false; + } + + return true; + } + }; + + bool hasIvarAssignedAPlusOneObject(PropsTy &props) const { + for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { + PlusOneAssign oneAssign(I->IvarD); + bool notFound = oneAssign.TraverseDecl(CurImplD); + if (!notFound) + return true; + } + + return false; + } + bool hasIvarWithExplicitOwnership(PropsTy &props) const { for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { if (isUserDeclared(I->IvarD)) { @@ -305,9 +372,9 @@ private: return false; } - bool hasNoBackingIvars(PropsTy &props) const { + bool hasAllIvarsBacked(PropsTy &props) const { for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) - if (I->IvarD) + if (!isUserDeclared(I->IvarD)) return false; return true; diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp index ed6ed0a..394f848 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp @@ -25,7 +25,6 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { @@ -130,10 +129,9 @@ public: // Change the -release to "receiver = nil" in a finally to avoid a leak // when an exception is thrown. Pass.TA.replace(E->getSourceRange(), rec->getSourceRange()); - if (Pass.Ctx.Idents.get("nil").hasMacroDefinition()) - Pass.TA.insertAfterToken(rec->getLocEnd(), " = nil"); - else - Pass.TA.insertAfterToken(rec->getLocEnd(), " = 0"); + std::string str = " = "; + str += getNilString(Pass.Ctx); + Pass.TA.insertAfterToken(rec->getLocEnd(), str); return true; } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp index 1cacd6d..69fb2e8 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -36,25 +36,32 @@ #include "Internals.h" #include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/Sema/SemaDiagnostic.h" +#include "clang/AST/ParentMap.h" #include "clang/Basic/SourceManager.h" using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{ MigrationPass &Pass; IdentifierInfo *SelfII; + llvm::OwningPtr<ParentMap> StmtMap; + public: UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) { SelfII = &Pass.Ctx.Idents.get("self"); } + void transformBody(Stmt *body) { + StmtMap.reset(new ParentMap(body)); + TraverseStmt(body); + } + bool VisitCastExpr(CastExpr *E) { - if (E->getCastKind() != CK_AnyPointerToObjCPointerCast + if (E->getCastKind() != CK_CPointerToObjCPointerCast && E->getCastKind() != CK_BitCast) return true; @@ -139,13 +146,21 @@ private: } void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) { + Transaction Trans(Pass.TA); + rewriteToBridgedCast(E, Kind, Trans); + } + + void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind, + Transaction &Trans) { TransformActions &TA = Pass.TA; // We will remove the compiler diagnostic. if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast, diag::err_arc_cast_requires_bridge, - E->getLocStart())) + E->getLocStart())) { + Trans.abort(); return; + } StringRef bridge; switch(Kind) { @@ -157,7 +172,6 @@ private: bridge = "__bridge_retained "; break; } - Transaction Trans(TA); TA.clearDiagnostic(diag::err_arc_mismatched_cast, diag::err_arc_cast_requires_bridge, E->getLocStart()); @@ -168,7 +182,7 @@ private: llvm::SmallString<128> newCast; newCast += '('; newCast += bridge; - newCast += E->getType().getAsString(Pass.Ctx.PrintingPolicy); + newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); newCast += ')'; if (isa<ParenExpr>(E->getSubExpr())) { @@ -181,16 +195,111 @@ private: } } + void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) { + Transaction Trans(Pass.TA); + Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange()); + rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans); + } + void transformObjCToNonObjCCast(CastExpr *E) { if (isSelf(E->getSubExpr())) return rewriteToBridgedCast(E, OBC_Bridge); + + CallExpr *callE; + if (isPassedToCFRetain(E, callE)) + return rewriteCastForCFRetain(E, callE); + + ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr()); + if (family == OMF_retain) + return rewriteToBridgedCast(E, OBC_BridgeRetained); + + if (family == OMF_autorelease || family == OMF_release) { + std::string err = "it is not safe to cast to '"; + err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); + err += "' the result of '"; + err += family == OMF_autorelease ? "autorelease" : "release"; + err += "' message; a __bridge cast may result in a pointer to a " + "destroyed object and a __bridge_retained may leak the object"; + Pass.TA.reportError(err, E->getLocStart(), + E->getSubExpr()->getSourceRange()); + Stmt *parent = E; + do { + parent = StmtMap->getParentIgnoreParenImpCasts(parent); + } while (parent && isa<ExprWithCleanups>(parent)); + + if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) { + std::string note = "remove the cast and change return type of function " + "to '"; + note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy()); + note += "' to have the object automatically autoreleased"; + Pass.TA.reportNote(note, retS->getLocStart()); + } + } + + if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getSubExpr())){ + if (implCE->getCastKind() == CK_ARCConsumeObject) + return rewriteToBridgedCast(E, OBC_BridgeRetained); + if (implCE->getCastKind() == CK_ARCReclaimReturnedObject) + return rewriteToBridgedCast(E, OBC_Bridge); + } + + bool isConsumed = false; + if (isPassedToCParamWithKnownOwnership(E, isConsumed)) + return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained + : OBC_Bridge); } - bool isSelf(Expr *E) { + static ObjCMethodFamily getFamilyOfMessage(Expr *E) { + E = E->IgnoreParenCasts(); + if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) + return ME->getMethodFamily(); + + return OMF_None; + } + + bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const { + if ((callE = dyn_cast_or_null<CallExpr>( + StmtMap->getParentIgnoreParenImpCasts(E)))) + if (FunctionDecl * + FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) + if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && + FD->getParent()->isTranslationUnit() && + FD->getLinkage() == ExternalLinkage) + return true; + + return false; + } + + bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const { + if (CallExpr *callE = dyn_cast_or_null<CallExpr>( + StmtMap->getParentIgnoreParenImpCasts(E))) + if (FunctionDecl * + FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) { + unsigned i = 0; + for (unsigned e = callE->getNumArgs(); i != e; ++i) { + Expr *arg = callE->getArg(i); + if (arg == E || arg->IgnoreParenImpCasts() == E) + break; + } + if (i < callE->getNumArgs()) { + ParmVarDecl *PD = FD->getParamDecl(i); + if (PD->getAttr<CFConsumedAttr>()) { + isConsumed = true; + return true; + } + } + } + + return false; + } + + bool isSelf(Expr *E) const { E = E->IgnoreParenLValueCasts(); if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) - if (DRE->getDecl()->getIdentifier() == SelfII) - return true; + if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl())) + if (IPD->getIdentifier() == SelfII) + return true; + return false; } }; @@ -198,6 +307,6 @@ private: } // end anonymous namespace void trans::rewriteUnbridgedCasts(MigrationPass &pass) { - UnbridgedCastRewriter trans(pass); + BodyTransform<UnbridgedCastRewriter> trans(pass); trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnusedInitDelegate.cpp index 1019ab4..e2aa6ff 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnusedInitDelegate.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnusedInitDelegate.cpp @@ -27,7 +27,6 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp index 07ccf70..1dbe811 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp @@ -19,7 +19,6 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; namespace { diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp index c99940b..ec676e9 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp @@ -13,10 +13,8 @@ #include "clang/Basic/SourceManager.h" #include "llvm/ADT/DenseSet.h" #include <map> - using namespace clang; using namespace arcmt; -using llvm::StringRef; namespace { @@ -46,9 +44,9 @@ class TransformActionsImpl { ActionKind Kind; SourceLocation Loc; SourceRange R1, R2; - llvm::StringRef Text1, Text2; + StringRef Text1, Text2; Stmt *S; - llvm::SmallVector<unsigned, 2> DiagIDs; + SmallVector<unsigned, 2> DiagIDs; }; std::vector<ActionData> CachedActions; @@ -70,11 +68,11 @@ class TransformActionsImpl { SourceLocation beginLoc = range.getBegin(), endLoc = range.getEnd(); assert(beginLoc.isValid() && endLoc.isValid()); if (range.isTokenRange()) { - Begin = FullSourceLoc(srcMgr.getInstantiationLoc(beginLoc), srcMgr); + Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr); End = FullSourceLoc(getLocForEndOfToken(endLoc, srcMgr, PP), srcMgr); } else { - Begin = FullSourceLoc(srcMgr.getInstantiationLoc(beginLoc), srcMgr); - End = FullSourceLoc(srcMgr.getInstantiationLoc(endLoc), srcMgr); + Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr); + End = FullSourceLoc(srcMgr.getExpansionLoc(endLoc), srcMgr); } assert(Begin.isValid() && End.isValid()); } @@ -104,7 +102,7 @@ class TransformActionsImpl { } }; - typedef llvm::SmallVector<StringRef, 2> TextsVec; + typedef SmallVector<StringRef, 2> TextsVec; typedef std::map<FullSourceLoc, TextsVec, FullSourceLoc::BeforeThanCompare> InsertsMap; InsertsMap Inserts; @@ -130,19 +128,19 @@ public: bool isInTransaction() const { return IsInTransaction; } - void insert(SourceLocation loc, llvm::StringRef text); - void insertAfterToken(SourceLocation loc, llvm::StringRef text); + void insert(SourceLocation loc, StringRef text); + void insertAfterToken(SourceLocation loc, StringRef text); void remove(SourceRange range); void removeStmt(Stmt *S); - void replace(SourceRange range, llvm::StringRef text); + void replace(SourceRange range, StringRef text); void replace(SourceRange range, SourceRange replacementRange); - void replaceStmt(Stmt *S, llvm::StringRef text); - void replaceText(SourceLocation loc, llvm::StringRef text, - llvm::StringRef replacementText); + void replaceStmt(Stmt *S, StringRef text); + void replaceText(SourceLocation loc, StringRef text, + StringRef replacementText); void increaseIndentation(SourceRange range, SourceLocation parentIndent); - bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range); + bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); void applyRewrites(TransformActions::RewriteReceiver &receiver); @@ -151,17 +149,17 @@ private: bool canInsertAfterToken(SourceLocation loc); bool canRemoveRange(SourceRange range); bool canReplaceRange(SourceRange range, SourceRange replacementRange); - bool canReplaceText(SourceLocation loc, llvm::StringRef text); + bool canReplaceText(SourceLocation loc, StringRef text); void commitInsert(SourceLocation loc, StringRef text); void commitInsertAfterToken(SourceLocation loc, StringRef text); void commitRemove(SourceRange range); void commitRemoveStmt(Stmt *S); void commitReplace(SourceRange range, SourceRange replacementRange); - void commitReplaceText(SourceLocation loc, llvm::StringRef text, - llvm::StringRef replacementText); + void commitReplaceText(SourceLocation loc, StringRef text, + StringRef replacementText); void commitIncreaseIndentation(SourceRange range,SourceLocation parentIndent); - void commitClearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range); + void commitClearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); void addRemoval(CharSourceRange range); void addInsertion(SourceLocation loc, StringRef text); @@ -364,7 +362,7 @@ void TransformActionsImpl::increaseIndentation(SourceRange range, CachedActions.push_back(data); } -bool TransformActionsImpl::clearDiagnostic(llvm::ArrayRef<unsigned> IDs, +bool TransformActionsImpl::clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) { assert(IsInTransaction && "Actions only allowed during a transaction"); if (!CapturedDiags.hasDiagnostic(IDs, range)) @@ -383,7 +381,7 @@ bool TransformActionsImpl::canInsert(SourceLocation loc) { return false; SourceManager &SM = Ctx.getSourceManager(); - if (SM.isInSystemHeader(SM.getInstantiationLoc(loc))) + if (SM.isInSystemHeader(SM.getExpansionLoc(loc))) return false; if (loc.isFileID()) @@ -396,7 +394,7 @@ bool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) { return false; SourceManager &SM = Ctx.getSourceManager(); - if (SM.isInSystemHeader(SM.getInstantiationLoc(loc))) + if (SM.isInSystemHeader(SM.getExpansionLoc(loc))) return false; if (loc.isFileID()) @@ -418,14 +416,14 @@ bool TransformActionsImpl::canReplaceText(SourceLocation loc, StringRef text) { return false; SourceManager &SM = Ctx.getSourceManager(); - loc = SM.getInstantiationLoc(loc); + loc = SM.getExpansionLoc(loc); // Break down the source location. std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); // Try to load the file buffer. bool invalidTemp = false; - llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); if (invalidTemp) return false; @@ -479,9 +477,9 @@ void TransformActionsImpl::commitReplaceText(SourceLocation loc, StringRef text, StringRef replacementText) { SourceManager &SM = Ctx.getSourceManager(); - loc = SM.getInstantiationLoc(loc); + loc = SM.getExpansionLoc(loc); // canReplaceText already checked if loc points at text. - SourceLocation afterText = loc.getFileLocWithOffset(text.size()); + SourceLocation afterText = loc.getLocWithOffset(text.size()); addRemoval(CharSourceRange::getCharRange(loc, afterText)); commitInsert(loc, replacementText); @@ -493,17 +491,17 @@ void TransformActionsImpl::commitIncreaseIndentation(SourceRange range, IndentationRanges.push_back( std::make_pair(CharRange(CharSourceRange::getTokenRange(range), SM, PP), - SM.getInstantiationLoc(parentIndent))); + SM.getExpansionLoc(parentIndent))); } -void TransformActionsImpl::commitClearDiagnostic(llvm::ArrayRef<unsigned> IDs, +void TransformActionsImpl::commitClearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) { CapturedDiags.clearDiagnostic(IDs, range); } void TransformActionsImpl::addInsertion(SourceLocation loc, StringRef text) { SourceManager &SM = Ctx.getSourceManager(); - loc = SM.getInstantiationLoc(loc); + loc = SM.getExpansionLoc(loc); for (std::list<CharRange>::reverse_iterator I = Removals.rbegin(), E = Removals.rend(); I != E; ++I) { if (!SM.isBeforeInTranslationUnit(loc, I->End)) @@ -591,16 +589,16 @@ SourceLocation TransformActionsImpl::getLocForEndOfToken(SourceLocation loc, SourceManager &SM, Preprocessor &PP) { if (loc.isMacroID()) - loc = SM.getInstantiationRange(loc).second; + loc = SM.getExpansionRange(loc).second; return PP.getLocForEndOfToken(loc); } TransformActions::RewriteReceiver::~RewriteReceiver() { } -TransformActions::TransformActions(Diagnostic &diag, +TransformActions::TransformActions(DiagnosticsEngine &diag, CapturedDiagList &capturedDiags, ASTContext &ctx, Preprocessor &PP) - : Diags(diag), CapturedDiags(capturedDiags) { + : Diags(diag), CapturedDiags(capturedDiags), ReportedErrors(false) { Impl = new TransformActionsImpl(capturedDiags, ctx, PP); } @@ -621,12 +619,12 @@ void TransformActions::abortTransaction() { } -void TransformActions::insert(SourceLocation loc, llvm::StringRef text) { +void TransformActions::insert(SourceLocation loc, StringRef text) { static_cast<TransformActionsImpl*>(Impl)->insert(loc, text); } void TransformActions::insertAfterToken(SourceLocation loc, - llvm::StringRef text) { + StringRef text) { static_cast<TransformActionsImpl*>(Impl)->insertAfterToken(loc, text); } @@ -638,7 +636,7 @@ void TransformActions::removeStmt(Stmt *S) { static_cast<TransformActionsImpl*>(Impl)->removeStmt(S); } -void TransformActions::replace(SourceRange range, llvm::StringRef text) { +void TransformActions::replace(SourceRange range, StringRef text) { static_cast<TransformActionsImpl*>(Impl)->replace(range, text); } @@ -647,12 +645,12 @@ void TransformActions::replace(SourceRange range, static_cast<TransformActionsImpl*>(Impl)->replace(range, replacementRange); } -void TransformActions::replaceStmt(Stmt *S, llvm::StringRef text) { +void TransformActions::replaceStmt(Stmt *S, StringRef text) { static_cast<TransformActionsImpl*>(Impl)->replaceStmt(S, text); } -void TransformActions::replaceText(SourceLocation loc, llvm::StringRef text, - llvm::StringRef replacementText) { +void TransformActions::replaceText(SourceLocation loc, StringRef text, + StringRef replacementText) { static_cast<TransformActionsImpl*>(Impl)->replaceText(loc, text, replacementText); } @@ -663,7 +661,7 @@ void TransformActions::increaseIndentation(SourceRange range, parentIndent); } -bool TransformActions::clearDiagnostic(llvm::ArrayRef<unsigned> IDs, +bool TransformActions::clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) { return static_cast<TransformActionsImpl*>(Impl)->clearDiagnostic(IDs, range); } @@ -672,7 +670,7 @@ void TransformActions::applyRewrites(RewriteReceiver &receiver) { static_cast<TransformActionsImpl*>(Impl)->applyRewrites(receiver); } -void TransformActions::reportError(llvm::StringRef error, SourceLocation loc, +void TransformActions::reportError(StringRef error, SourceLocation loc, SourceRange range) { assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() && "Errors should be emitted out of a transaction"); @@ -683,9 +681,10 @@ void TransformActions::reportError(llvm::StringRef error, SourceLocation loc, = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error, rewriteErr); Diags.Report(loc, diagID) << range; + ReportedErrors = true; } -void TransformActions::reportNote(llvm::StringRef note, SourceLocation loc, +void TransformActions::reportNote(StringRef note, SourceLocation loc, SourceRange range) { assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() && "Errors should be emitted out of a transaction"); diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.cpp index 7bd95e5..4244faf 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.cpp @@ -23,7 +23,6 @@ using namespace clang; using namespace arcmt; using namespace trans; -using llvm::StringRef; //===----------------------------------------------------------------------===// // Helpers. @@ -92,11 +91,23 @@ bool trans::canApplyWeak(ASTContext &Ctx, QualType type) { /// source location will be invalid. SourceLocation trans::findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx) { + SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx); + if (SemiLoc.isInvalid()) + return SourceLocation(); + return SemiLoc.getLocWithOffset(1); +} + +/// \brief \arg Loc is the end of a statement range. This returns the location +/// of the semicolon following the statement. +/// If no semicolon is found or the location is inside a macro, the returned +/// source location will be invalid. +SourceLocation trans::findSemiAfterLocation(SourceLocation loc, + ASTContext &Ctx) { SourceManager &SM = Ctx.getSourceManager(); if (loc.isMacroID()) { if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOptions())) return SourceLocation(); - loc = SM.getInstantiationRange(loc).second; + loc = SM.getExpansionRange(loc).second; } loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions()); @@ -105,7 +116,7 @@ SourceLocation trans::findLocationAfterSemi(SourceLocation loc, // Try to load the file buffer. bool invalidTemp = false; - llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); if (invalidTemp) return SourceLocation(); @@ -120,7 +131,7 @@ SourceLocation trans::findLocationAfterSemi(SourceLocation loc, if (tok.isNot(tok::semi)) return SourceLocation(); - return tok.getLocation().getFileLocWithOffset(1); + return tok.getLocation(); } bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) { @@ -155,7 +166,8 @@ bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) { bool trans::isGlobalVar(Expr *E) { E = E->IgnoreParenCasts(); if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) - return DRE->getDecl()->getDeclContext()->isFileContext(); + return DRE->getDecl()->getDeclContext()->isFileContext() && + DRE->getDecl()->getLinkage() == ExternalLinkage; if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) return isGlobalVar(condOp->getTrueExpr()) && isGlobalVar(condOp->getFalseExpr()); @@ -163,6 +175,13 @@ bool trans::isGlobalVar(Expr *E) { return false; } +StringRef trans::getNilString(ASTContext &Ctx) { + if (Ctx.Idents.get("nil").hasMacroDefinition()) + return "nil"; + else + return "0"; +} + namespace { class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> { @@ -283,6 +302,7 @@ static void independentTransforms(MigrationPass &pass) { makeAssignARCSafe(pass); rewriteUnbridgedCasts(pass); rewriteBlockObjCVariable(pass); + checkAPIUses(pass); } std::vector<TransformFn> arcmt::getAllTransformations() { diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.h b/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.h index b47d6d8..5e4db56 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.h +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.h @@ -37,6 +37,7 @@ void removeZeroOutPropsInDealloc(MigrationPass &pass); void rewriteProperties(MigrationPass &pass); void rewriteBlockObjCVariable(MigrationPass &pass); void rewriteUnusedInitDelegate(MigrationPass &pass); +void checkAPIUses(MigrationPass &pass); void removeEmptyStatementsAndDealloc(MigrationPass &pass); @@ -53,9 +54,16 @@ bool canApplyWeak(ASTContext &Ctx, QualType type); /// source location will be invalid. SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx); +/// \brief \arg Loc is the end of a statement range. This returns the location +/// of the semicolon following the statement. +/// If no semicolon is found or the location is inside a macro, the returned +/// source location will be invalid. +SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx); + bool hasSideEffects(Expr *E, ASTContext &Ctx); bool isGlobalVar(Expr *E); - +/// \brief Returns "nil" or "0" if 'nil' macro is not actually defined. +StringRef getNilString(ASTContext &Ctx); template <typename BODY_TRANS> class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > { @@ -65,7 +73,8 @@ public: BodyTransform(MigrationPass &pass) : Pass(pass) { } bool TraverseStmt(Stmt *rootS) { - BODY_TRANS(Pass).transformBody(rootS); + if (rootS) + BODY_TRANS(Pass).transformBody(rootS); return true; } }; |