diff options
author | Alp Toker <alp@nuanti.com> | 2014-07-16 16:48:33 +0000 |
---|---|---|
committer | Alp Toker <alp@nuanti.com> | 2014-07-16 16:48:33 +0000 |
commit | 0621cb2e7dfd89f558a045f145f900b62379dcc2 (patch) | |
tree | fe7aa0e9718ccaa2199ec99044c72add529205d8 /clang/lib/Rewrite | |
parent | db829de6d6a3dd4c13b0ee75ac35e42b7b92b7e6 (diff) | |
download | llvm-0621cb2e7dfd89f558a045f145f900b62379dcc2.tar.gz |
Make clang's rewrite engine a core feature
The rewrite facility's footprint is small so it's not worth going to these
lengths to support disabling at configure time, particularly since key compiler
features now depend on it.
Meanwhile the Objective-C rewriters have been moved under the
ENABLE_CLANG_ARCMT umbrella for now as they're comparatively heavy and still
potentially worth excluding from lightweight builds.
Tests are now passing with any combination of feature flags. The flags
historically haven't been tested by LLVM's build servers so caveat emptor.
llvm-svn: 213171
Diffstat (limited to 'clang/lib/Rewrite')
19 files changed, 23 insertions, 15072 deletions
diff --git a/clang/lib/Rewrite/CMakeLists.txt b/clang/lib/Rewrite/CMakeLists.txt index d3d75430233f..0c77536012aa 100644 --- a/clang/lib/Rewrite/CMakeLists.txt +++ b/clang/lib/Rewrite/CMakeLists.txt @@ -1,2 +1,16 @@ -add_subdirectory(Core) -add_subdirectory(Frontend) +set(LLVM_LINK_COMPONENTS + Support + ) + +add_clang_library(clangRewrite + DeltaTree.cpp + HTMLRewrite.cpp + RewriteRope.cpp + Rewriter.cpp + TokenRewriter.cpp + + LINK_LIBS + clangAST + clangBasic + clangLex + ) diff --git a/clang/lib/Rewrite/Core/CMakeLists.txt b/clang/lib/Rewrite/Core/CMakeLists.txt deleted file mode 100644 index 896382c36dbd..000000000000 --- a/clang/lib/Rewrite/Core/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set(LLVM_LINK_COMPONENTS - Support - ) - -add_clang_library(clangRewriteCore - DeltaTree.cpp - HTMLRewrite.cpp - RewriteRope.cpp - Rewriter.cpp - TokenRewriter.cpp - - LINK_LIBS - clangAST - clangBasic - clangLex - ) diff --git a/clang/lib/Rewrite/Core/Makefile b/clang/lib/Rewrite/Core/Makefile deleted file mode 100644 index 8c8d2e478135..000000000000 --- a/clang/lib/Rewrite/Core/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- clang/lib/Rewrite/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 / rewriting facilities. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../../.. -LIBRARYNAME := clangRewriteCore - -include $(CLANG_LEVEL)/Makefile - diff --git a/clang/lib/Rewrite/Core/DeltaTree.cpp b/clang/lib/Rewrite/DeltaTree.cpp index 352fab077a2e..352fab077a2e 100644 --- a/clang/lib/Rewrite/Core/DeltaTree.cpp +++ b/clang/lib/Rewrite/DeltaTree.cpp diff --git a/clang/lib/Rewrite/Frontend/CMakeLists.txt b/clang/lib/Rewrite/Frontend/CMakeLists.txt deleted file mode 100644 index 85af97d343d2..000000000000 --- a/clang/lib/Rewrite/Frontend/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -set(LLVM_LINK_COMPONENTS - Support - ) - -add_clang_library(clangRewriteFrontend - FixItRewriter.cpp - FrontendActions.cpp - HTMLPrint.cpp - InclusionRewriter.cpp - RewriteMacros.cpp - RewriteModernObjC.cpp - RewriteObjC.cpp - RewriteTest.cpp - - LINK_LIBS - clangAST - clangBasic - clangEdit - clangFrontend - clangLex - clangRewriteCore - ) diff --git a/clang/lib/Rewrite/Frontend/FixItRewriter.cpp b/clang/lib/Rewrite/Frontend/FixItRewriter.cpp deleted file mode 100644 index 8b7af7166c8f..000000000000 --- a/clang/lib/Rewrite/Frontend/FixItRewriter.cpp +++ /dev/null @@ -1,200 +0,0 @@ -//===--- FixItRewriter.cpp - Fix-It Rewriter Diagnostic Client --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a diagnostic client adaptor that performs rewrites as -// suggested by code modification hints attached to diagnostics. It -// then forwards any diagnostics to the adapted diagnostic client. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Frontend/FixItRewriter.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceLocation.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Edit/Commit.h" -#include "clang/Edit/EditsReceiver.h" -#include "clang/Frontend/FrontendDiagnostic.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include <cstdio> -#include <memory> - -using namespace clang; - -FixItRewriter::FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr, - const LangOptions &LangOpts, - FixItOptions *FixItOpts) - : Diags(Diags), - Editor(SourceMgr, LangOpts), - Rewrite(SourceMgr, LangOpts), - FixItOpts(FixItOpts), - NumFailures(0), - PrevDiagSilenced(false) { - OwnsClient = Diags.ownsClient(); - Client = Diags.takeClient(); - Diags.setClient(this); -} - -FixItRewriter::~FixItRewriter() { - Diags.takeClient(); - Diags.setClient(Client, OwnsClient); -} - -bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) { - const RewriteBuffer *RewriteBuf = Rewrite.getRewriteBufferFor(ID); - if (!RewriteBuf) return true; - RewriteBuf->write(OS); - OS.flush(); - return false; -} - -namespace { - -class RewritesReceiver : public edit::EditsReceiver { - Rewriter &Rewrite; - -public: - RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { } - - void insert(SourceLocation loc, StringRef text) override { - Rewrite.InsertText(loc, text); - } - void replace(CharSourceRange range, StringRef text) override { - Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text); - } -}; - -} - -bool FixItRewriter::WriteFixedFiles( - std::vector<std::pair<std::string, std::string> > *RewrittenFiles) { - if (NumFailures > 0 && !FixItOpts->FixWhatYouCan) { - Diag(FullSourceLoc(), diag::warn_fixit_no_changes); - return true; - } - - RewritesReceiver Rec(Rewrite); - Editor.applyRewrites(Rec); - - for (iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) { - const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first); - int fd; - std::string Filename = FixItOpts->RewriteFilename(Entry->getName(), fd); - std::string Err; - std::unique_ptr<llvm::raw_fd_ostream> OS; - if (fd != -1) { - OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true)); - } else { - OS.reset(new llvm::raw_fd_ostream(Filename.c_str(), Err, - llvm::sys::fs::F_None)); - } - if (!Err.empty()) { - Diags.Report(clang::diag::err_fe_unable_to_open_output) - << Filename << Err; - continue; - } - RewriteBuffer &RewriteBuf = I->second; - RewriteBuf.write(*OS); - OS->flush(); - - if (RewrittenFiles) - RewrittenFiles->push_back(std::make_pair(Entry->getName(), Filename)); - } - - return false; -} - -bool FixItRewriter::IncludeInDiagnosticCounts() const { - return Client ? Client->IncludeInDiagnosticCounts() : true; -} - -void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, - const Diagnostic &Info) { - // Default implementation (Warnings/errors count). - DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); - - if (!FixItOpts->Silent || - DiagLevel >= DiagnosticsEngine::Error || - (DiagLevel == DiagnosticsEngine::Note && !PrevDiagSilenced) || - (DiagLevel > DiagnosticsEngine::Note && Info.getNumFixItHints())) { - Client->HandleDiagnostic(DiagLevel, Info); - PrevDiagSilenced = false; - } else { - PrevDiagSilenced = true; - } - - // Skip over any diagnostics that are ignored or notes. - if (DiagLevel <= DiagnosticsEngine::Note) - return; - // Skip over errors if we are only fixing warnings. - if (DiagLevel >= DiagnosticsEngine::Error && FixItOpts->FixOnlyWarnings) { - ++NumFailures; - return; - } - - // Make sure that we can perform all of the modifications we - // in this diagnostic. - edit::Commit commit(Editor); - for (unsigned Idx = 0, Last = Info.getNumFixItHints(); - Idx < Last; ++Idx) { - const FixItHint &Hint = Info.getFixItHint(Idx); - - if (Hint.CodeToInsert.empty()) { - if (Hint.InsertFromRange.isValid()) - commit.insertFromRange(Hint.RemoveRange.getBegin(), - Hint.InsertFromRange, /*afterToken=*/false, - Hint.BeforePreviousInsertions); - else - commit.remove(Hint.RemoveRange); - } else { - if (Hint.RemoveRange.isTokenRange() || - Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd()) - commit.replace(Hint.RemoveRange, Hint.CodeToInsert); - else - commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert, - /*afterToken=*/false, Hint.BeforePreviousInsertions); - } - } - bool CanRewrite = Info.getNumFixItHints() > 0 && commit.isCommitable(); - - if (!CanRewrite) { - if (Info.getNumFixItHints() > 0) - Diag(Info.getLocation(), diag::note_fixit_in_macro); - - // If this was an error, refuse to perform any rewriting. - if (DiagLevel >= DiagnosticsEngine::Error) { - if (++NumFailures == 1) - Diag(Info.getLocation(), diag::note_fixit_unfixed_error); - } - return; - } - - if (!Editor.commit(commit)) { - ++NumFailures; - Diag(Info.getLocation(), diag::note_fixit_failed); - return; - } - - Diag(Info.getLocation(), diag::note_fixit_applied); -} - -/// \brief Emit a diagnostic via the adapted diagnostic client. -void FixItRewriter::Diag(SourceLocation Loc, unsigned DiagID) { - // When producing this diagnostic, we temporarily bypass ourselves, - // clear out any current diagnostic, and let the downstream client - // format the diagnostic. - Diags.takeClient(); - Diags.setClient(Client); - Diags.Clear(); - Diags.Report(Loc, DiagID); - Diags.takeClient(); - Diags.setClient(this); -} - -FixItOptions::~FixItOptions() {} diff --git a/clang/lib/Rewrite/Frontend/FrontendActions.cpp b/clang/lib/Rewrite/Frontend/FrontendActions.cpp deleted file mode 100644 index 4394e993a415..000000000000 --- a/clang/lib/Rewrite/Frontend/FrontendActions.cpp +++ /dev/null @@ -1,192 +0,0 @@ -//===--- FrontendActions.cpp ----------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Frontend/FrontendActions.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/Basic/FileManager.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Frontend/FrontendDiagnostic.h" -#include "clang/Frontend/Utils.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Parse/Parser.h" -#include "clang/Rewrite/Frontend/ASTConsumers.h" -#include "clang/Rewrite/Frontend/FixItRewriter.h" -#include "clang/Rewrite/Frontend/Rewriters.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include <memory> - -using namespace clang; - -//===----------------------------------------------------------------------===// -// AST Consumer Actions -//===----------------------------------------------------------------------===// - -ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { - if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) - return CreateHTMLPrinter(OS, CI.getPreprocessor()); - return nullptr; -} - -FixItAction::FixItAction() {} -FixItAction::~FixItAction() {} - -ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { - return new ASTConsumer(); -} - -namespace { -class FixItRewriteInPlace : public FixItOptions { -public: - std::string RewriteFilename(const std::string &Filename, int &fd) override { - fd = -1; - return Filename; - } -}; - -class FixItActionSuffixInserter : public FixItOptions { - std::string NewSuffix; - -public: - FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan) - : NewSuffix(NewSuffix) { - this->FixWhatYouCan = FixWhatYouCan; - } - - std::string RewriteFilename(const std::string &Filename, int &fd) override { - fd = -1; - SmallString<128> Path(Filename); - llvm::sys::path::replace_extension(Path, - NewSuffix + llvm::sys::path::extension(Path)); - return Path.str(); - } -}; - -class FixItRewriteToTemp : public FixItOptions { -public: - std::string RewriteFilename(const std::string &Filename, int &fd) override { - SmallString<128> Path; - llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename), - llvm::sys::path::extension(Filename), fd, - Path); - return Path.str(); - } -}; -} // end anonymous namespace - -bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) { - const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); - if (!FEOpts.FixItSuffix.empty()) { - FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix, - FEOpts.FixWhatYouCan)); - } else { - FixItOpts.reset(new FixItRewriteInPlace); - FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan; - } - Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), - CI.getLangOpts(), FixItOpts.get())); - return true; -} - -void FixItAction::EndSourceFileAction() { - // Otherwise rewrite all files. - Rewriter->WriteFixedFiles(); -} - -bool FixItRecompile::BeginInvocation(CompilerInstance &CI) { - - std::vector<std::pair<std::string, std::string> > RewrittenFiles; - bool err = false; - { - const FrontendOptions &FEOpts = CI.getFrontendOpts(); - std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction()); - if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) { - std::unique_ptr<FixItOptions> FixItOpts; - if (FEOpts.FixToTemporaries) - FixItOpts.reset(new FixItRewriteToTemp()); - else - FixItOpts.reset(new FixItRewriteInPlace()); - FixItOpts->Silent = true; - FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan; - FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings; - FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(), - CI.getLangOpts(), FixItOpts.get()); - FixAction->Execute(); - - err = Rewriter.WriteFixedFiles(&RewrittenFiles); - - FixAction->EndSourceFile(); - CI.setSourceManager(nullptr); - CI.setFileManager(nullptr); - } else { - err = true; - } - } - if (err) - return false; - CI.getDiagnosticClient().clear(); - CI.getDiagnostics().Reset(); - - PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); - PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(), - RewrittenFiles.begin(), RewrittenFiles.end()); - PPOpts.RemappedFilesKeepOriginalName = false; - - return true; -} - -//===----------------------------------------------------------------------===// -// Preprocessor Actions -//===----------------------------------------------------------------------===// - -ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { - if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) { - if (CI.getLangOpts().ObjCRuntime.isNonFragile()) - return CreateModernObjCRewriter(InFile, OS, - CI.getDiagnostics(), CI.getLangOpts(), - CI.getDiagnosticOpts().NoRewriteMacros, - (CI.getCodeGenOpts().getDebugInfo() != - CodeGenOptions::NoDebugInfo)); - return CreateObjCRewriter(InFile, OS, - CI.getDiagnostics(), CI.getLangOpts(), - CI.getDiagnosticOpts().NoRewriteMacros); - } - return nullptr; -} - -void RewriteMacrosAction::ExecuteAction() { - CompilerInstance &CI = getCompilerInstance(); - raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); - if (!OS) return; - - RewriteMacrosInInput(CI.getPreprocessor(), OS); -} - -void RewriteTestAction::ExecuteAction() { - CompilerInstance &CI = getCompilerInstance(); - raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); - if (!OS) return; - - DoRewriteTest(CI.getPreprocessor(), OS); -} - -void RewriteIncludesAction::ExecuteAction() { - CompilerInstance &CI = getCompilerInstance(); - raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); - if (!OS) return; - - RewriteIncludesInInput(CI.getPreprocessor(), OS, - CI.getPreprocessorOutputOpts()); -} diff --git a/clang/lib/Rewrite/Frontend/HTMLPrint.cpp b/clang/lib/Rewrite/Frontend/HTMLPrint.cpp deleted file mode 100644 index 64da05fdde61..000000000000 --- a/clang/lib/Rewrite/Frontend/HTMLPrint.cpp +++ /dev/null @@ -1,94 +0,0 @@ -//===--- HTMLPrint.cpp - Source code -> HTML pretty-printing --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Pretty-printing of source code to HTML. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Frontend/ASTConsumers.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Rewrite/Core/HTMLRewrite.h" -#include "clang/Rewrite/Core/Rewriter.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// Functional HTML pretty-printing. -//===----------------------------------------------------------------------===// - -namespace { - class HTMLPrinter : public ASTConsumer { - Rewriter R; - raw_ostream *Out; - Preprocessor &PP; - bool SyntaxHighlight, HighlightMacros; - - public: - HTMLPrinter(raw_ostream *OS, Preprocessor &pp, - bool _SyntaxHighlight, bool _HighlightMacros) - : Out(OS), PP(pp), SyntaxHighlight(_SyntaxHighlight), - HighlightMacros(_HighlightMacros) {} - - void Initialize(ASTContext &context) override; - void HandleTranslationUnit(ASTContext &Ctx) override; - }; -} - -ASTConsumer* clang::CreateHTMLPrinter(raw_ostream *OS, - Preprocessor &PP, - bool SyntaxHighlight, - bool HighlightMacros) { - return new HTMLPrinter(OS, PP, SyntaxHighlight, HighlightMacros); -} - -void HTMLPrinter::Initialize(ASTContext &context) { - R.setSourceMgr(context.getSourceManager(), context.getLangOpts()); -} - -void HTMLPrinter::HandleTranslationUnit(ASTContext &Ctx) { - if (PP.getDiagnostics().hasErrorOccurred()) - return; - - // Format the file. - FileID FID = R.getSourceMgr().getMainFileID(); - const FileEntry* Entry = R.getSourceMgr().getFileEntryForID(FID); - const char* Name; - // In some cases, in particular the case where the input is from stdin, - // there is no entry. Fall back to the memory buffer for a name in those - // cases. - if (Entry) - Name = Entry->getName(); - else - Name = R.getSourceMgr().getBuffer(FID)->getBufferIdentifier(); - - html::AddLineNumbers(R, FID); - html::AddHeaderFooterInternalBuiltinCSS(R, FID, Name); - - // If we have a preprocessor, relex the file and syntax highlight. - // We might not have a preprocessor if we come from a deserialized AST file, - // for example. - - if (SyntaxHighlight) html::SyntaxHighlight(R, FID, PP); - if (HighlightMacros) html::HighlightMacros(R, FID, PP); - html::EscapeText(R, FID, false, true); - - // Emit the HTML. - const RewriteBuffer &RewriteBuf = R.getEditBuffer(FID); - char *Buffer = (char*)malloc(RewriteBuf.size()); - std::copy(RewriteBuf.begin(), RewriteBuf.end(), Buffer); - Out->write(Buffer, RewriteBuf.size()); - free(Buffer); -} diff --git a/clang/lib/Rewrite/Frontend/InclusionRewriter.cpp b/clang/lib/Rewrite/Frontend/InclusionRewriter.cpp deleted file mode 100644 index aa7017baee26..000000000000 --- a/clang/lib/Rewrite/Frontend/InclusionRewriter.cpp +++ /dev/null @@ -1,547 +0,0 @@ -//===--- InclusionRewriter.cpp - Rewrite includes into their expansions ---===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This code rewrites include invocations into their expansions. This gives you -// a file with all included files merged into it. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Frontend/Rewriters.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Frontend/PreprocessorOutputOptions.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/Pragma.h" -#include "clang/Lex/Preprocessor.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/raw_ostream.h" - -using namespace clang; -using namespace llvm; - -namespace { - -class InclusionRewriter : public PPCallbacks { - /// Information about which #includes were actually performed, - /// created by preprocessor callbacks. - struct FileChange { - const Module *Mod; - SourceLocation From; - FileID Id; - SrcMgr::CharacteristicKind FileType; - FileChange(SourceLocation From, const Module *Mod) : Mod(Mod), From(From) { - } - }; - Preprocessor &PP; ///< Used to find inclusion directives. - SourceManager &SM; ///< Used to read and manage source files. - raw_ostream &OS; ///< The destination stream for rewritten contents. - const llvm::MemoryBuffer *PredefinesBuffer; ///< The preprocessor predefines. - bool ShowLineMarkers; ///< Show #line markers. - bool UseLineDirective; ///< Use of line directives or line markers. - typedef std::map<unsigned, FileChange> FileChangeMap; - FileChangeMap FileChanges; ///< Tracks which files were included where. - /// Used transitively for building up the FileChanges mapping over the - /// various \c PPCallbacks callbacks. - FileChangeMap::iterator LastInsertedFileChange; -public: - InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers); - bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType); - void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) { - PredefinesBuffer = Buf; - } -private: - void FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType, - FileID PrevFID) override; - void FileSkipped(const FileEntry &ParentFile, const Token &FilenameTok, - SrcMgr::CharacteristicKind FileType) override; - void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, - StringRef FileName, bool IsAngled, - CharSourceRange FilenameRange, const FileEntry *File, - StringRef SearchPath, StringRef RelativePath, - const Module *Imported) override; - void WriteLineInfo(const char *Filename, int Line, - SrcMgr::CharacteristicKind FileType, - StringRef EOL, StringRef Extra = StringRef()); - void WriteImplicitModuleImport(const Module *Mod, StringRef EOL); - void OutputContentUpTo(const MemoryBuffer &FromFile, - unsigned &WriteFrom, unsigned WriteTo, - StringRef EOL, int &lines, - bool EnsureNewline); - void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, - const MemoryBuffer &FromFile, StringRef EOL, - unsigned &NextToWrite, int &Lines); - bool HandleHasInclude(FileID FileId, Lexer &RawLex, - const DirectoryLookup *Lookup, Token &Tok, - bool &FileExists); - const FileChange *FindFileChangeLocation(SourceLocation Loc) const; - StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken); -}; - -} // end anonymous namespace - -/// Initializes an InclusionRewriter with a \p PP source and \p OS destination. -InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS, - bool ShowLineMarkers) - : PP(PP), SM(PP.getSourceManager()), OS(OS), PredefinesBuffer(nullptr), - ShowLineMarkers(ShowLineMarkers), - LastInsertedFileChange(FileChanges.end()) { - // If we're in microsoft mode, use normal #line instead of line markers. - UseLineDirective = PP.getLangOpts().MicrosoftExt; -} - -/// Write appropriate line information as either #line directives or GNU line -/// markers depending on what mode we're in, including the \p Filename and -/// \p Line we are located at, using the specified \p EOL line separator, and -/// any \p Extra context specifiers in GNU line directives. -void InclusionRewriter::WriteLineInfo(const char *Filename, int Line, - SrcMgr::CharacteristicKind FileType, - StringRef EOL, StringRef Extra) { - if (!ShowLineMarkers) - return; - if (UseLineDirective) { - OS << "#line" << ' ' << Line << ' ' << '"'; - OS.write_escaped(Filename); - OS << '"'; - } else { - // Use GNU linemarkers as described here: - // http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html - OS << '#' << ' ' << Line << ' ' << '"'; - OS.write_escaped(Filename); - OS << '"'; - if (!Extra.empty()) - OS << Extra; - if (FileType == SrcMgr::C_System) - // "`3' This indicates that the following text comes from a system header - // file, so certain warnings should be suppressed." - OS << " 3"; - else if (FileType == SrcMgr::C_ExternCSystem) - // as above for `3', plus "`4' This indicates that the following text - // should be treated as being wrapped in an implicit extern "C" block." - OS << " 3 4"; - } - OS << EOL; -} - -void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod, - StringRef EOL) { - OS << "@import " << Mod->getFullModuleName() << ";" - << " /* clang -frewrite-includes: implicit import */" << EOL; -} - -/// FileChanged - Whenever the preprocessor enters or exits a #include file -/// it invokes this handler. -void InclusionRewriter::FileChanged(SourceLocation Loc, - FileChangeReason Reason, - SrcMgr::CharacteristicKind NewFileType, - FileID) { - if (Reason != EnterFile) - return; - if (LastInsertedFileChange == FileChanges.end()) - // we didn't reach this file (eg: the main file) via an inclusion directive - return; - LastInsertedFileChange->second.Id = FullSourceLoc(Loc, SM).getFileID(); - LastInsertedFileChange->second.FileType = NewFileType; - LastInsertedFileChange = FileChanges.end(); -} - -/// Called whenever an inclusion is skipped due to canonical header protection -/// macros. -void InclusionRewriter::FileSkipped(const FileEntry &/*ParentFile*/, - const Token &/*FilenameTok*/, - SrcMgr::CharacteristicKind /*FileType*/) { - assert(LastInsertedFileChange != FileChanges.end() && "A file, that wasn't " - "found via an inclusion directive, was skipped"); - FileChanges.erase(LastInsertedFileChange); - LastInsertedFileChange = FileChanges.end(); -} - -/// This should be called whenever the preprocessor encounters include -/// directives. It does not say whether the file has been included, but it -/// provides more information about the directive (hash location instead -/// of location inside the included file). It is assumed that the matching -/// FileChanged() or FileSkipped() is called after this. -void InclusionRewriter::InclusionDirective(SourceLocation HashLoc, - const Token &/*IncludeTok*/, - StringRef /*FileName*/, - bool /*IsAngled*/, - CharSourceRange /*FilenameRange*/, - const FileEntry * /*File*/, - StringRef /*SearchPath*/, - StringRef /*RelativePath*/, - const Module *Imported) { - assert(LastInsertedFileChange == FileChanges.end() && "Another inclusion " - "directive was found before the previous one was processed"); - std::pair<FileChangeMap::iterator, bool> p = FileChanges.insert( - std::make_pair(HashLoc.getRawEncoding(), FileChange(HashLoc, Imported))); - assert(p.second && "Unexpected revisitation of the same include directive"); - if (!Imported) - LastInsertedFileChange = p.first; -} - -/// Simple lookup for a SourceLocation (specifically one denoting the hash in -/// an inclusion directive) in the map of inclusion information, FileChanges. -const InclusionRewriter::FileChange * -InclusionRewriter::FindFileChangeLocation(SourceLocation Loc) const { - FileChangeMap::const_iterator I = FileChanges.find(Loc.getRawEncoding()); - if (I != FileChanges.end()) - return &I->second; - return nullptr; -} - -/// Detect the likely line ending style of \p FromFile by examining the first -/// newline found within it. -static StringRef DetectEOL(const MemoryBuffer &FromFile) { - // detect what line endings the file uses, so that added content does not mix - // the style - const char *Pos = strchr(FromFile.getBufferStart(), '\n'); - if (!Pos) - return "\n"; - if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r') - return "\n\r"; - if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] == '\r') - return "\r\n"; - return "\n"; -} - -/// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at -/// \p WriteTo - 1. -void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile, - unsigned &WriteFrom, unsigned WriteTo, - StringRef EOL, int &Line, - bool EnsureNewline) { - if (WriteTo <= WriteFrom) - return; - if (&FromFile == PredefinesBuffer) { - // Ignore the #defines of the predefines buffer. - WriteFrom = WriteTo; - return; - } - OS.write(FromFile.getBufferStart() + WriteFrom, WriteTo - WriteFrom); - // count lines manually, it's faster than getPresumedLoc() - Line += std::count(FromFile.getBufferStart() + WriteFrom, - FromFile.getBufferStart() + WriteTo, '\n'); - if (EnsureNewline) { - char LastChar = FromFile.getBufferStart()[WriteTo - 1]; - if (LastChar != '\n' && LastChar != '\r') - OS << EOL; - } - WriteFrom = WriteTo; -} - -/// Print characters from \p FromFile starting at \p NextToWrite up until the -/// inclusion directive at \p StartToken, then print out the inclusion -/// inclusion directive disabled by a #if directive, updating \p NextToWrite -/// and \p Line to track the number of source lines visited and the progress -/// through the \p FromFile buffer. -void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex, - const Token &StartToken, - const MemoryBuffer &FromFile, - StringRef EOL, - unsigned &NextToWrite, int &Line) { - OutputContentUpTo(FromFile, NextToWrite, - SM.getFileOffset(StartToken.getLocation()), EOL, Line, false); - Token DirectiveToken; - do { - DirectiveLex.LexFromRawLexer(DirectiveToken); - } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof)); - if (&FromFile == PredefinesBuffer) { - // OutputContentUpTo() would not output anything anyway. - return; - } - OS << "#if 0 /* expanded by -frewrite-includes */" << EOL; - OutputContentUpTo(FromFile, NextToWrite, - SM.getFileOffset(DirectiveToken.getLocation()) + DirectiveToken.getLength(), - EOL, Line, true); - OS << "#endif /* expanded by -frewrite-includes */" << EOL; -} - -/// Find the next identifier in the pragma directive specified by \p RawToken. -StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex, - Token &RawToken) { - RawLex.LexFromRawLexer(RawToken); - if (RawToken.is(tok::raw_identifier)) - PP.LookUpIdentifierInfo(RawToken); - if (RawToken.is(tok::identifier)) - return RawToken.getIdentifierInfo()->getName(); - return StringRef(); -} - -// Expand __has_include and __has_include_next if possible. If there's no -// definitive answer return false. -bool InclusionRewriter::HandleHasInclude( - FileID FileId, Lexer &RawLex, const DirectoryLookup *Lookup, Token &Tok, - bool &FileExists) { - // Lex the opening paren. - RawLex.LexFromRawLexer(Tok); - if (Tok.isNot(tok::l_paren)) - return false; - - RawLex.LexFromRawLexer(Tok); - - SmallString<128> FilenameBuffer; - StringRef Filename; - // Since the raw lexer doesn't give us angle_literals we have to parse them - // ourselves. - // FIXME: What to do if the file name is a macro? - if (Tok.is(tok::less)) { - RawLex.LexFromRawLexer(Tok); - - FilenameBuffer += '<'; - do { - if (Tok.is(tok::eod)) // Sanity check. - return false; - - if (Tok.is(tok::raw_identifier)) - PP.LookUpIdentifierInfo(Tok); - - // Get the string piece. - SmallVector<char, 128> TmpBuffer; - bool Invalid = false; - StringRef TmpName = PP.getSpelling(Tok, TmpBuffer, &Invalid); - if (Invalid) - return false; - - FilenameBuffer += TmpName; - - RawLex.LexFromRawLexer(Tok); - } while (Tok.isNot(tok::greater)); - - FilenameBuffer += '>'; - Filename = FilenameBuffer; - } else { - if (Tok.isNot(tok::string_literal)) - return false; - - bool Invalid = false; - Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid); - if (Invalid) - return false; - } - - // Lex the closing paren. - RawLex.LexFromRawLexer(Tok); - if (Tok.isNot(tok::r_paren)) - return false; - - // Now ask HeaderInfo if it knows about the header. - // FIXME: Subframeworks aren't handled here. Do we care? - bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename); - const DirectoryLookup *CurDir; - const FileEntry *File = PP.getHeaderSearchInfo().LookupFile( - Filename, SourceLocation(), isAngled, nullptr, CurDir, - PP.getSourceManager().getFileEntryForID(FileId), nullptr, nullptr, - nullptr, false); - - FileExists = File != nullptr; - return true; -} - -/// Use a raw lexer to analyze \p FileId, incrementally copying parts of it -/// and including content of included files recursively. -bool InclusionRewriter::Process(FileID FileId, - SrcMgr::CharacteristicKind FileType) -{ - bool Invalid; - const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); - if (Invalid) // invalid inclusion - return false; - const char *FileName = FromFile.getBufferIdentifier(); - Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts()); - RawLex.SetCommentRetentionState(false); - - StringRef EOL = DetectEOL(FromFile); - - // Per the GNU docs: "1" indicates entering a new file. - if (FileId == SM.getMainFileID() || FileId == PP.getPredefinesFileID()) - WriteLineInfo(FileName, 1, FileType, EOL, ""); - else - WriteLineInfo(FileName, 1, FileType, EOL, " 1"); - - if (SM.getFileIDSize(FileId) == 0) - return false; - - // The next byte to be copied from the source file, which may be non-zero if - // the lexer handled a BOM. - unsigned NextToWrite = SM.getFileOffset(RawLex.getSourceLocation()); - assert(SM.getLineNumber(FileId, NextToWrite) == 1); - int Line = 1; // The current input file line number. - - Token RawToken; - RawLex.LexFromRawLexer(RawToken); - - // TODO: Consider adding a switch that strips possibly unimportant content, - // such as comments, to reduce the size of repro files. - while (RawToken.isNot(tok::eof)) { - if (RawToken.is(tok::hash) && RawToken.isAtStartOfLine()) { - RawLex.setParsingPreprocessorDirective(true); - Token HashToken = RawToken; - RawLex.LexFromRawLexer(RawToken); - if (RawToken.is(tok::raw_identifier)) - PP.LookUpIdentifierInfo(RawToken); - if (RawToken.getIdentifierInfo() != nullptr) { - switch (RawToken.getIdentifierInfo()->getPPKeywordID()) { - case tok::pp_include: - case tok::pp_include_next: - case tok::pp_import: { - CommentOutDirective(RawLex, HashToken, FromFile, EOL, NextToWrite, - Line); - if (FileId != PP.getPredefinesFileID()) - WriteLineInfo(FileName, Line - 1, FileType, EOL, ""); - StringRef LineInfoExtra; - if (const FileChange *Change = FindFileChangeLocation( - HashToken.getLocation())) { - if (Change->Mod) { - WriteImplicitModuleImport(Change->Mod, EOL); - - // else now include and recursively process the file - } else if (Process(Change->Id, Change->FileType)) { - // and set lineinfo back to this file, if the nested one was - // actually included - // `2' indicates returning to a file (after having included - // another file. - LineInfoExtra = " 2"; - } - } - // fix up lineinfo (since commented out directive changed line - // numbers) for inclusions that were skipped due to header guards - WriteLineInfo(FileName, Line, FileType, EOL, LineInfoExtra); - break; - } - case tok::pp_pragma: { - StringRef Identifier = NextIdentifierName(RawLex, RawToken); - if (Identifier == "clang" || Identifier == "GCC") { - if (NextIdentifierName(RawLex, RawToken) == "system_header") { - // keep the directive in, commented out - CommentOutDirective(RawLex, HashToken, FromFile, EOL, - NextToWrite, Line); - // update our own type - FileType = SM.getFileCharacteristic(RawToken.getLocation()); - WriteLineInfo(FileName, Line, FileType, EOL); - } - } else if (Identifier == "once") { - // keep the directive in, commented out - CommentOutDirective(RawLex, HashToken, FromFile, EOL, - NextToWrite, Line); - WriteLineInfo(FileName, Line, FileType, EOL); - } - break; - } - case tok::pp_if: - case tok::pp_elif: { - bool elif = (RawToken.getIdentifierInfo()->getPPKeywordID() == - tok::pp_elif); - // Rewrite special builtin macros to avoid pulling in host details. - do { - // Walk over the directive. - RawLex.LexFromRawLexer(RawToken); - if (RawToken.is(tok::raw_identifier)) - PP.LookUpIdentifierInfo(RawToken); - - if (RawToken.is(tok::identifier)) { - bool HasFile; - SourceLocation Loc = RawToken.getLocation(); - - // Rewrite __has_include(x) - if (RawToken.getIdentifierInfo()->isStr("__has_include")) { - if (!HandleHasInclude(FileId, RawLex, nullptr, RawToken, - HasFile)) - continue; - // Rewrite __has_include_next(x) - } else if (RawToken.getIdentifierInfo()->isStr( - "__has_include_next")) { - const DirectoryLookup *Lookup = PP.GetCurDirLookup(); - if (Lookup) - ++Lookup; - - if (!HandleHasInclude(FileId, RawLex, Lookup, RawToken, - HasFile)) - continue; - } else { - continue; - } - // Replace the macro with (0) or (1), followed by the commented - // out macro for reference. - OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc), - EOL, Line, false); - OS << '(' << (int) HasFile << ")/*"; - OutputContentUpTo(FromFile, NextToWrite, - SM.getFileOffset(RawToken.getLocation()) + - RawToken.getLength(), - EOL, Line, false); - OS << "*/"; - } - } while (RawToken.isNot(tok::eod)); - if (elif) { - OutputContentUpTo(FromFile, NextToWrite, - SM.getFileOffset(RawToken.getLocation()) + - RawToken.getLength(), - EOL, Line, /*EnsureNewLine*/ true); - WriteLineInfo(FileName, Line, FileType, EOL); - } - break; - } - case tok::pp_endif: - case tok::pp_else: { - // We surround every #include by #if 0 to comment it out, but that - // changes line numbers. These are fixed up right after that, but - // the whole #include could be inside a preprocessor conditional - // that is not processed. So it is necessary to fix the line - // numbers one the next line after each #else/#endif as well. - RawLex.SetKeepWhitespaceMode(true); - do { - RawLex.LexFromRawLexer(RawToken); - } while (RawToken.isNot(tok::eod) && RawToken.isNot(tok::eof)); - OutputContentUpTo( - FromFile, NextToWrite, - SM.getFileOffset(RawToken.getLocation()) + RawToken.getLength(), - EOL, Line, /*EnsureNewLine*/ true); - WriteLineInfo(FileName, Line, FileType, EOL); - RawLex.SetKeepWhitespaceMode(false); - } - default: - break; - } - } - RawLex.setParsingPreprocessorDirective(false); - } - RawLex.LexFromRawLexer(RawToken); - } - OutputContentUpTo(FromFile, NextToWrite, - SM.getFileOffset(SM.getLocForEndOfFile(FileId)), EOL, Line, - /*EnsureNewline*/true); - return true; -} - -/// InclusionRewriterInInput - Implement -frewrite-includes mode. -void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, - const PreprocessorOutputOptions &Opts) { - SourceManager &SM = PP.getSourceManager(); - InclusionRewriter *Rewrite = new InclusionRewriter(PP, *OS, - Opts.ShowLineMarkers); - PP.addPPCallbacks(Rewrite); - PP.IgnorePragmas(); - - // First let the preprocessor process the entire file and call callbacks. - // Callbacks will record which #include's were actually performed. - PP.EnterMainSourceFile(); - Token Tok; - // Only preprocessor directives matter here, so disable macro expansion - // everywhere else as an optimization. - // TODO: It would be even faster if the preprocessor could be switched - // to a mode where it would parse only preprocessor directives and comments, - // nothing else matters for parsing or processing. - PP.SetMacroExpansionOnlyInDirectives(); - do { - PP.Lex(Tok); - } while (Tok.isNot(tok::eof)); - Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID())); - Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User); - Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User); - OS->flush(); -} diff --git a/clang/lib/Rewrite/Frontend/Makefile b/clang/lib/Rewrite/Frontend/Makefile deleted file mode 100644 index ac97d4074ecb..000000000000 --- a/clang/lib/Rewrite/Frontend/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- clang/lib/Rewrite/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 / rewriting facilities. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../../.. -LIBRARYNAME := clangRewriteFrontend - -include $(CLANG_LEVEL)/Makefile - diff --git a/clang/lib/Rewrite/Frontend/RewriteMacros.cpp b/clang/lib/Rewrite/Frontend/RewriteMacros.cpp deleted file mode 100644 index 0d0a991fa6f9..000000000000 --- a/clang/lib/Rewrite/Frontend/RewriteMacros.cpp +++ /dev/null @@ -1,217 +0,0 @@ -//===--- RewriteMacros.cpp - Rewrite macros into their expansions ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This code rewrites macro invocations into their expansions. This gives you -// a macro expanded file that retains comments and #includes. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Frontend/Rewriters.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Rewrite/Core/Rewriter.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include <cstdio> -#include <memory> - -using namespace clang; - -/// isSameToken - Return true if the two specified tokens start have the same -/// content. -static bool isSameToken(Token &RawTok, Token &PPTok) { - // If two tokens have the same kind and the same identifier info, they are - // obviously the same. - if (PPTok.getKind() == RawTok.getKind() && - PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo()) - return true; - - // Otherwise, if they are different but have the same identifier info, they - // are also considered to be the same. This allows keywords and raw lexed - // identifiers with the same name to be treated the same. - if (PPTok.getIdentifierInfo() && - PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo()) - return true; - - return false; -} - - -/// GetNextRawTok - Return the next raw token in the stream, skipping over -/// comments if ReturnComment is false. -static const Token &GetNextRawTok(const std::vector<Token> &RawTokens, - unsigned &CurTok, bool ReturnComment) { - assert(CurTok < RawTokens.size() && "Overran eof!"); - - // If the client doesn't want comments and we have one, skip it. - if (!ReturnComment && RawTokens[CurTok].is(tok::comment)) - ++CurTok; - - return RawTokens[CurTok++]; -} - - -/// LexRawTokensFromMainFile - Lets all the raw tokens from the main file into -/// the specified vector. -static void LexRawTokensFromMainFile(Preprocessor &PP, - std::vector<Token> &RawTokens) { - SourceManager &SM = PP.getSourceManager(); - - // Create a lexer to lex all the tokens of the main file in raw mode. Even - // though it is in raw mode, it will not return comments. - const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); - Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts()); - - // Switch on comment lexing because we really do want them. - RawLex.SetCommentRetentionState(true); - - Token RawTok; - do { - RawLex.LexFromRawLexer(RawTok); - - // If we have an identifier with no identifier info for our raw token, look - // up the indentifier info. This is important for equality comparison of - // identifier tokens. - if (RawTok.is(tok::raw_identifier)) - PP.LookUpIdentifierInfo(RawTok); - - RawTokens.push_back(RawTok); - } while (RawTok.isNot(tok::eof)); -} - - -/// RewriteMacrosInInput - Implement -rewrite-macros mode. -void clang::RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS) { - SourceManager &SM = PP.getSourceManager(); - - Rewriter Rewrite; - Rewrite.setSourceMgr(SM, PP.getLangOpts()); - RewriteBuffer &RB = Rewrite.getEditBuffer(SM.getMainFileID()); - - std::vector<Token> RawTokens; - LexRawTokensFromMainFile(PP, RawTokens); - unsigned CurRawTok = 0; - Token RawTok = GetNextRawTok(RawTokens, CurRawTok, false); - - - // Get the first preprocessing token. - PP.EnterMainSourceFile(); - Token PPTok; - PP.Lex(PPTok); - - // Preprocess the input file in parallel with raw lexing the main file. Ignore - // all tokens that are preprocessed from a file other than the main file (e.g. - // a header). If we see tokens that are in the preprocessed file but not the - // lexed file, we have a macro expansion. If we see tokens in the lexed file - // that aren't in the preprocessed view, we have macros that expand to no - // tokens, or macro arguments etc. - while (RawTok.isNot(tok::eof) || PPTok.isNot(tok::eof)) { - SourceLocation PPLoc = SM.getExpansionLoc(PPTok.getLocation()); - - // If PPTok is from a different source file, ignore it. - if (!SM.isWrittenInMainFile(PPLoc)) { - PP.Lex(PPTok); - continue; - } - - // If the raw file hits a preprocessor directive, they will be extra tokens - // in the raw file that don't exist in the preprocsesed file. However, we - // choose to preserve them in the output file and otherwise handle them - // specially. - if (RawTok.is(tok::hash) && RawTok.isAtStartOfLine()) { - // If this is a #warning directive or #pragma mark (GNU extensions), - // comment the line out. - if (RawTokens[CurRawTok].is(tok::identifier)) { - const IdentifierInfo *II = RawTokens[CurRawTok].getIdentifierInfo(); - if (II->getName() == "warning") { - // Comment out #warning. - RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); - } else if (II->getName() == "pragma" && - RawTokens[CurRawTok+1].is(tok::identifier) && - (RawTokens[CurRawTok+1].getIdentifierInfo()->getName() == - "mark")) { - // Comment out #pragma mark. - RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); - } - } - - // Otherwise, if this is a #include or some other directive, just leave it - // in the file by skipping over the line. - RawTok = GetNextRawTok(RawTokens, CurRawTok, false); - while (!RawTok.isAtStartOfLine() && RawTok.isNot(tok::eof)) - RawTok = GetNextRawTok(RawTokens, CurRawTok, false); - continue; - } - - // Okay, both tokens are from the same file. Get their offsets from the - // start of the file. - unsigned PPOffs = SM.getFileOffset(PPLoc); - unsigned RawOffs = SM.getFileOffset(RawTok.getLocation()); - - // If the offsets are the same and the token kind is the same, ignore them. - if (PPOffs == RawOffs && isSameToken(RawTok, PPTok)) { - RawTok = GetNextRawTok(RawTokens, CurRawTok, false); - PP.Lex(PPTok); - continue; - } - - // If the PP token is farther along than the raw token, something was - // deleted. Comment out the raw token. - if (RawOffs <= PPOffs) { - // Comment out a whole run of tokens instead of bracketing each one with - // comments. Add a leading space if RawTok didn't have one. - bool HasSpace = RawTok.hasLeadingSpace(); - RB.InsertTextAfter(RawOffs, &" /*"[HasSpace]); - unsigned EndPos; - - do { - EndPos = RawOffs+RawTok.getLength(); - - RawTok = GetNextRawTok(RawTokens, CurRawTok, true); - RawOffs = SM.getFileOffset(RawTok.getLocation()); - - if (RawTok.is(tok::comment)) { - // Skip past the comment. - RawTok = GetNextRawTok(RawTokens, CurRawTok, false); - break; - } - - } while (RawOffs <= PPOffs && !RawTok.isAtStartOfLine() && - (PPOffs != RawOffs || !isSameToken(RawTok, PPTok))); - - RB.InsertTextBefore(EndPos, "*/"); - continue; - } - - // Otherwise, there was a replacement an expansion. Insert the new token - // in the output buffer. Insert the whole run of new tokens at once to get - // them in the right order. - unsigned InsertPos = PPOffs; - std::string Expansion; - while (PPOffs < RawOffs) { - Expansion += ' ' + PP.getSpelling(PPTok); - PP.Lex(PPTok); - PPLoc = SM.getExpansionLoc(PPTok.getLocation()); - PPOffs = SM.getFileOffset(PPLoc); - } - Expansion += ' '; - RB.InsertTextBefore(InsertPos, Expansion); - } - - // Get the buffer corresponding to MainFileID. If we haven't changed it, then - // we are done. - if (const RewriteBuffer *RewriteBuf = - Rewrite.getRewriteBufferFor(SM.getMainFileID())) { - //printf("Changed:\n"); - *OS << std::string(RewriteBuf->begin(), RewriteBuf->end()); - } else { - fprintf(stderr, "No changes\n"); - } - OS->flush(); -} diff --git a/clang/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/clang/lib/Rewrite/Frontend/RewriteModernObjC.cpp deleted file mode 100644 index 43de31c516e0..000000000000 --- a/clang/lib/Rewrite/Frontend/RewriteModernObjC.cpp +++ /dev/null @@ -1,7756 +0,0 @@ -//===--- RewriteObjC.cpp - Playground for the code rewriter ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Hacks and fun related to the code rewriter. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Frontend/ASTConsumers.h" -#include "clang/AST/AST.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/Attr.h" -#include "clang/AST/ParentMap.h" -#include "clang/Basic/CharInfo.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Lex/Lexer.h" -#include "clang/Rewrite/Core/Rewriter.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include <memory> - -using namespace clang; -using llvm::utostr; - -namespace { - class RewriteModernObjC : public ASTConsumer { - protected: - - enum { - BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), - block, ... */ - BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */ - BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the - __block variable */ - BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy - helpers */ - BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose - support routines */ - BLOCK_BYREF_CURRENT_MAX = 256 - }; - - enum { - BLOCK_NEEDS_FREE = (1 << 24), - BLOCK_HAS_COPY_DISPOSE = (1 << 25), - BLOCK_HAS_CXX_OBJ = (1 << 26), - BLOCK_IS_GC = (1 << 27), - BLOCK_IS_GLOBAL = (1 << 28), - BLOCK_HAS_DESCRIPTOR = (1 << 29) - }; - - Rewriter Rewrite; - DiagnosticsEngine &Diags; - const LangOptions &LangOpts; - ASTContext *Context; - SourceManager *SM; - TranslationUnitDecl *TUDecl; - FileID MainFileID; - const char *MainFileStart, *MainFileEnd; - Stmt *CurrentBody; - ParentMap *PropParentMap; // created lazily. - std::string InFileName; - raw_ostream* OutFile; - std::string Preamble; - - TypeDecl *ProtocolTypeDecl; - VarDecl *GlobalVarDecl; - Expr *GlobalConstructionExp; - unsigned RewriteFailedDiag; - unsigned GlobalBlockRewriteFailedDiag; - // ObjC string constant support. - unsigned NumObjCStringLiterals; - VarDecl *ConstantStringClassReference; - RecordDecl *NSStringRecord; - - // ObjC foreach break/continue generation support. - int BcLabelCount; - - unsigned TryFinallyContainsReturnDiag; - // Needed for super. - ObjCMethodDecl *CurMethodDef; - RecordDecl *SuperStructDecl; - RecordDecl *ConstantStringDecl; - - FunctionDecl *MsgSendFunctionDecl; - FunctionDecl *MsgSendSuperFunctionDecl; - FunctionDecl *MsgSendStretFunctionDecl; - FunctionDecl *MsgSendSuperStretFunctionDecl; - FunctionDecl *MsgSendFpretFunctionDecl; - FunctionDecl *GetClassFunctionDecl; - FunctionDecl *GetMetaClassFunctionDecl; - FunctionDecl *GetSuperClassFunctionDecl; - FunctionDecl *SelGetUidFunctionDecl; - FunctionDecl *CFStringFunctionDecl; - FunctionDecl *SuperConstructorFunctionDecl; - FunctionDecl *CurFunctionDef; - - /* Misc. containers needed for meta-data rewrite. */ - SmallVector<ObjCImplementationDecl *, 8> ClassImplementation; - SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation; - llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs; - llvm::SmallPtrSet<ObjCProtocolDecl*, 8> ObjCSynthesizedProtocols; - llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCWrittenInterfaces; - llvm::SmallPtrSet<TagDecl*, 32> GlobalDefinedTags; - SmallVector<ObjCInterfaceDecl*, 32> ObjCInterfacesSeen; - /// DefinedNonLazyClasses - List of defined "non-lazy" classes. - SmallVector<ObjCInterfaceDecl*, 8> DefinedNonLazyClasses; - - /// DefinedNonLazyCategories - List of defined "non-lazy" categories. - SmallVector<ObjCCategoryDecl *, 8> DefinedNonLazyCategories; - - SmallVector<Stmt *, 32> Stmts; - SmallVector<int, 8> ObjCBcLabelNo; - // Remember all the @protocol(<expr>) expressions. - llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls; - - llvm::DenseSet<uint64_t> CopyDestroyCache; - - // Block expressions. - SmallVector<BlockExpr *, 32> Blocks; - SmallVector<int, 32> InnerDeclRefsCount; - SmallVector<DeclRefExpr *, 32> InnerDeclRefs; - - SmallVector<DeclRefExpr *, 32> BlockDeclRefs; - - - // Block related declarations. - SmallVector<ValueDecl *, 8> BlockByCopyDecls; - llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet; - SmallVector<ValueDecl *, 8> BlockByRefDecls; - llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet; - llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo; - llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls; - llvm::SmallPtrSet<VarDecl *, 8> ImportedLocalExternalDecls; - - llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs; - llvm::DenseMap<ObjCInterfaceDecl *, - llvm::SmallPtrSet<ObjCIvarDecl *, 8> > ReferencedIvars; - - // ivar bitfield grouping containers - llvm::DenseSet<const ObjCInterfaceDecl *> ObjCInterefaceHasBitfieldGroups; - llvm::DenseMap<const ObjCIvarDecl* , unsigned> IvarGroupNumber; - // This container maps an <class, group number for ivar> tuple to the type - // of the struct where the bitfield belongs. - llvm::DenseMap<std::pair<const ObjCInterfaceDecl*, unsigned>, QualType> GroupRecordType; - SmallVector<FunctionDecl*, 32> FunctionDefinitionsSeen; - - // This maps an original source AST to it's rewritten form. This allows - // us to avoid rewriting the same node twice (which is very uncommon). - // This is needed to support some of the exotic property rewriting. - llvm::DenseMap<Stmt *, Stmt *> ReplacedNodes; - - // Needed for header files being rewritten - bool IsHeader; - bool SilenceRewriteMacroWarning; - bool GenerateLineInfo; - bool objc_impl_method; - - bool DisableReplaceStmt; - class DisableReplaceStmtScope { - RewriteModernObjC &R; - bool SavedValue; - - public: - DisableReplaceStmtScope(RewriteModernObjC &R) - : R(R), SavedValue(R.DisableReplaceStmt) { - R.DisableReplaceStmt = true; - } - ~DisableReplaceStmtScope() { - R.DisableReplaceStmt = SavedValue; - } - }; - void InitializeCommon(ASTContext &context); - - public: - llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames; - // Top Level Driver code. - bool HandleTopLevelDecl(DeclGroupRef D) override { - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { - if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*I)) { - if (!Class->isThisDeclarationADefinition()) { - RewriteForwardClassDecl(D); - break; - } else { - // Keep track of all interface declarations seen. - ObjCInterfacesSeen.push_back(Class); - break; - } - } - - if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*I)) { - if (!Proto->isThisDeclarationADefinition()) { - RewriteForwardProtocolDecl(D); - break; - } - } - - if (FunctionDecl *FDecl = dyn_cast<FunctionDecl>(*I)) { - // Under modern abi, we cannot translate body of the function - // yet until all class extensions and its implementation is seen. - // This is because they may introduce new bitfields which must go - // into their grouping struct. - if (FDecl->isThisDeclarationADefinition() && - // Not c functions defined inside an objc container. - !FDecl->isTopLevelDeclInObjCContainer()) { - FunctionDefinitionsSeen.push_back(FDecl); - break; - } - } - HandleTopLevelSingleDecl(*I); - } - return true; - } - - void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override { - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(*I)) { - if (isTopLevelBlockPointerType(TD->getUnderlyingType())) - RewriteBlockPointerDecl(TD); - else if (TD->getUnderlyingType()->isFunctionPointerType()) - CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - else - RewriteObjCQualifiedInterfaceTypes(TD); - } - } - return; - } - - void HandleTopLevelSingleDecl(Decl *D); - void HandleDeclInMainFile(Decl *D); - RewriteModernObjC(std::string inFile, raw_ostream *OS, - DiagnosticsEngine &D, const LangOptions &LOpts, - bool silenceMacroWarn, bool LineInfo); - - ~RewriteModernObjC() {} - - void HandleTranslationUnit(ASTContext &C) override; - - void ReplaceStmt(Stmt *Old, Stmt *New) { - Stmt *ReplacingStmt = ReplacedNodes[Old]; - - if (ReplacingStmt) - return; // We can't rewrite the same node twice. - - if (DisableReplaceStmt) - return; - - // If replacement succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceStmt(Old, New)) { - ReplacedNodes[Old] = New; - return; - } - if (SilenceRewriteMacroWarning) - return; - Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) - << Old->getSourceRange(); - } - - void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) { - assert(Old != nullptr && New != nullptr && "Expected non-null Stmt's"); - if (DisableReplaceStmt) - return; - - // Measure the old text. - int Size = Rewrite.getRangeSize(SrcRange); - if (Size == -1) { - Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) - << Old->getSourceRange(); - return; - } - // Get the new text. - std::string SStr; - llvm::raw_string_ostream S(SStr); - New->printPretty(S, nullptr, PrintingPolicy(LangOpts)); - const std::string &Str = S.str(); - - // If replacement succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, Str)) { - ReplacedNodes[Old] = New; - return; - } - if (SilenceRewriteMacroWarning) - return; - Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) - << Old->getSourceRange(); - } - - void InsertText(SourceLocation Loc, StringRef Str, - bool InsertAfter = true) { - // If insertion succeeded or warning disabled return with no warning. - if (!Rewrite.InsertText(Loc, Str, InsertAfter) || - SilenceRewriteMacroWarning) - return; - - Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); - } - - void ReplaceText(SourceLocation Start, unsigned OrigLength, - StringRef Str) { - // If removal succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceText(Start, OrigLength, Str) || - SilenceRewriteMacroWarning) - return; - - Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag); - } - - // Syntactic Rewriting. - void RewriteRecordBody(RecordDecl *RD); - void RewriteInclude(); - void RewriteLineDirective(const Decl *D); - void ConvertSourceLocationToLineDirective(SourceLocation Loc, - std::string &LineString); - void RewriteForwardClassDecl(DeclGroupRef D); - void RewriteForwardClassDecl(const SmallVectorImpl<Decl *> &DG); - void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl, - const std::string &typedefString); - void RewriteImplementations(); - void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, - ObjCImplementationDecl *IMD, - ObjCCategoryImplDecl *CID); - void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl); - void RewriteImplementationDecl(Decl *Dcl); - void RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, - ObjCMethodDecl *MDecl, std::string &ResultStr); - void RewriteTypeIntoString(QualType T, std::string &ResultStr, - const FunctionType *&FPRetType); - void RewriteByRefString(std::string &ResultStr, const std::string &Name, - ValueDecl *VD, bool def=false); - void RewriteCategoryDecl(ObjCCategoryDecl *Dcl); - void RewriteProtocolDecl(ObjCProtocolDecl *Dcl); - void RewriteForwardProtocolDecl(DeclGroupRef D); - void RewriteForwardProtocolDecl(const SmallVectorImpl<Decl *> &DG); - void RewriteMethodDeclaration(ObjCMethodDecl *Method); - void RewriteProperty(ObjCPropertyDecl *prop); - void RewriteFunctionDecl(FunctionDecl *FD); - void RewriteBlockPointerType(std::string& Str, QualType Type); - void RewriteBlockPointerTypeVariable(std::string& Str, ValueDecl *VD); - void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD); - void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl); - void RewriteTypeOfDecl(VarDecl *VD); - void RewriteObjCQualifiedInterfaceTypes(Expr *E); - - std::string getIvarAccessString(ObjCIvarDecl *D); - - // Expression Rewriting. - Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S); - Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp); - Stmt *RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseudo); - Stmt *RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseudo); - Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp); - Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp); - Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp); - Stmt *RewriteObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Exp); - Stmt *RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp); - Stmt *RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp); - Stmt *RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral *Exp); - Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp); - Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); - Stmt *RewriteObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S); - Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); - Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S); - Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, - SourceLocation OrigEnd); - Stmt *RewriteBreakStmt(BreakStmt *S); - Stmt *RewriteContinueStmt(ContinueStmt *S); - void RewriteCastExpr(CStyleCastExpr *CE); - void RewriteImplicitCastObjCExpr(CastExpr *IE); - void RewriteLinkageSpec(LinkageSpecDecl *LSD); - - // Computes ivar bitfield group no. - unsigned ObjCIvarBitfieldGroupNo(ObjCIvarDecl *IV); - // Names field decl. for ivar bitfield group. - void ObjCIvarBitfieldGroupDecl(ObjCIvarDecl *IV, std::string &Result); - // Names struct type for ivar bitfield group. - void ObjCIvarBitfieldGroupType(ObjCIvarDecl *IV, std::string &Result); - // Names symbol for ivar bitfield group field offset. - void ObjCIvarBitfieldGroupOffset(ObjCIvarDecl *IV, std::string &Result); - // Given an ivar bitfield, it builds (or finds) its group record type. - QualType GetGroupRecordTypeForObjCIvarBitfield(ObjCIvarDecl *IV); - QualType SynthesizeBitfieldGroupStructType( - ObjCIvarDecl *IV, - SmallVectorImpl<ObjCIvarDecl *> &IVars); - - // Block rewriting. - void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D); - - // Block specific rewrite rules. - void RewriteBlockPointerDecl(NamedDecl *VD); - void RewriteByRefVar(VarDecl *VD, bool firstDecl, bool lastDecl); - Stmt *RewriteBlockDeclRefExpr(DeclRefExpr *VD); - Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE); - void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); - - void RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, - std::string &Result); - - void RewriteObjCFieldDecl(FieldDecl *fieldDecl, std::string &Result); - bool IsTagDefinedInsideClass(ObjCContainerDecl *IDecl, TagDecl *Tag, - bool &IsNamedDefinition); - void RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDecl, - std::string &Result); - - bool RewriteObjCFieldDeclType(QualType &Type, std::string &Result); - - void RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl, - std::string &Result); - - void Initialize(ASTContext &context) override; - - // Misc. AST transformation routines. Sometimes they end up calling - // rewriting routines on the new ASTs. - CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD, - Expr **args, unsigned nargs, - SourceLocation StartLoc=SourceLocation(), - SourceLocation EndLoc=SourceLocation()); - - Expr *SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, - QualType returnType, - SmallVectorImpl<QualType> &ArgTypes, - SmallVectorImpl<Expr*> &MsgExprs, - ObjCMethodDecl *Method); - - Stmt *SynthMessageExpr(ObjCMessageExpr *Exp, - SourceLocation StartLoc=SourceLocation(), - SourceLocation EndLoc=SourceLocation()); - - void SynthCountByEnumWithState(std::string &buf); - void SynthMsgSendFunctionDecl(); - void SynthMsgSendSuperFunctionDecl(); - void SynthMsgSendStretFunctionDecl(); - void SynthMsgSendFpretFunctionDecl(); - void SynthMsgSendSuperStretFunctionDecl(); - void SynthGetClassFunctionDecl(); - void SynthGetMetaClassFunctionDecl(); - void SynthGetSuperClassFunctionDecl(); - void SynthSelGetUidFunctionDecl(); - void SynthSuperConstructorFunctionDecl(); - - // Rewriting metadata - template<typename MethodIterator> - void RewriteObjCMethodsMetaData(MethodIterator MethodBegin, - MethodIterator MethodEnd, - bool IsInstanceMethod, - StringRef prefix, - StringRef ClassName, - std::string &Result); - void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol, - std::string &Result); - void RewriteObjCProtocolListMetaData( - const ObjCList<ObjCProtocolDecl> &Prots, - StringRef prefix, StringRef ClassName, std::string &Result); - void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, - std::string &Result); - void RewriteClassSetupInitHook(std::string &Result); - - void RewriteMetaDataIntoBuffer(std::string &Result); - void WriteImageInfo(std::string &Result); - void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl, - std::string &Result); - void RewriteCategorySetupInitHook(std::string &Result); - - // Rewriting ivar - void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, - std::string &Result); - Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV); - - - std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag); - std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - StringRef funcName, std::string Tag); - std::string SynthesizeBlockFunc(BlockExpr *CE, int i, - StringRef funcName, std::string Tag); - std::string SynthesizeBlockImpl(BlockExpr *CE, - std::string Tag, std::string Desc); - std::string SynthesizeBlockDescriptor(std::string DescTag, - std::string ImplTag, - int i, StringRef funcName, - unsigned hasCopy); - Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp); - void SynthesizeBlockLiterals(SourceLocation FunLocStart, - StringRef FunName); - FunctionDecl *SynthBlockInitFunctionDecl(StringRef name); - Stmt *SynthBlockInitExpr(BlockExpr *Exp, - const SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs); - - // Misc. helper routines. - QualType getProtocolType(); - void WarnAboutReturnGotoStmts(Stmt *S); - void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND); - void InsertBlockLiteralsWithinFunction(FunctionDecl *FD); - void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD); - - bool IsDeclStmtInForeachHeader(DeclStmt *DS); - void CollectBlockDeclRefInfo(BlockExpr *Exp); - void GetBlockDeclRefExprs(Stmt *S); - void GetInnerBlockDeclRefExprs(Stmt *S, - SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs, - llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts); - - // We avoid calling Type::isBlockPointerType(), since it operates on the - // canonical type. We only care if the top-level type is a closure pointer. - bool isTopLevelBlockPointerType(QualType T) { - return isa<BlockPointerType>(T); - } - - /// convertBlockPointerToFunctionPointer - Converts a block-pointer type - /// to a function pointer type and upon success, returns true; false - /// otherwise. - bool convertBlockPointerToFunctionPointer(QualType &T) { - if (isTopLevelBlockPointerType(T)) { - const BlockPointerType *BPT = T->getAs<BlockPointerType>(); - T = Context->getPointerType(BPT->getPointeeType()); - return true; - } - return false; - } - - bool convertObjCTypeToCStyleType(QualType &T); - - bool needToScanForQualifiers(QualType T); - QualType getSuperStructType(); - QualType getConstantStringStructType(); - QualType convertFunctionTypeOfBlocks(const FunctionType *FT); - bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf); - - void convertToUnqualifiedObjCType(QualType &T) { - if (T->isObjCQualifiedIdType()) { - bool isConst = T.isConstQualified(); - T = isConst ? Context->getObjCIdType().withConst() - : Context->getObjCIdType(); - } - else if (T->isObjCQualifiedClassType()) - T = Context->getObjCClassType(); - else if (T->isObjCObjectPointerType() && - T->getPointeeType()->isObjCQualifiedInterfaceType()) { - if (const ObjCObjectPointerType * OBJPT = - T->getAsObjCInterfacePointerType()) { - const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType(); - T = QualType(IFaceT, 0); - T = Context->getPointerType(T); - } - } - } - - // FIXME: This predicate seems like it would be useful to add to ASTContext. - bool isObjCType(QualType T) { - if (!LangOpts.ObjC1 && !LangOpts.ObjC2) - return false; - - QualType OCT = Context->getCanonicalType(T).getUnqualifiedType(); - - if (OCT == Context->getCanonicalType(Context->getObjCIdType()) || - OCT == Context->getCanonicalType(Context->getObjCClassType())) - return true; - - if (const PointerType *PT = OCT->getAs<PointerType>()) { - if (isa<ObjCInterfaceType>(PT->getPointeeType()) || - PT->getPointeeType()->isObjCQualifiedIdType()) - return true; - } - return false; - } - bool PointerTypeTakesAnyBlockArguments(QualType QT); - bool PointerTypeTakesAnyObjCQualifiedType(QualType QT); - void GetExtentOfArgList(const char *Name, const char *&LParen, - const char *&RParen); - - void QuoteDoublequotes(std::string &From, std::string &To) { - for (unsigned i = 0; i < From.length(); i++) { - if (From[i] == '"') - To += "\\\""; - else - To += From[i]; - } - } - - QualType getSimpleFunctionType(QualType result, - ArrayRef<QualType> args, - bool variadic = false) { - if (result == Context->getObjCInstanceType()) - result = Context->getObjCIdType(); - FunctionProtoType::ExtProtoInfo fpi; - fpi.Variadic = variadic; - return Context->getFunctionType(result, args, fpi); - } - - // Helper function: create a CStyleCastExpr with trivial type source info. - CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty, - CastKind Kind, Expr *E) { - TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation()); - return CStyleCastExpr::Create(*Ctx, Ty, VK_RValue, Kind, E, nullptr, - TInfo, SourceLocation(), SourceLocation()); - } - - bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const { - IdentifierInfo* II = &Context->Idents.get("load"); - Selector LoadSel = Context->Selectors.getSelector(0, &II); - return OD->getClassMethod(LoadSel) != nullptr; - } - - StringLiteral *getStringLiteral(StringRef Str) { - QualType StrType = Context->getConstantArrayType( - Context->CharTy, llvm::APInt(32, Str.size() + 1), ArrayType::Normal, - 0); - return StringLiteral::Create(*Context, Str, StringLiteral::Ascii, - /*Pascal=*/false, StrType, SourceLocation()); - } - }; - -} - -void RewriteModernObjC::RewriteBlocksInFunctionProtoType(QualType funcType, - NamedDecl *D) { - if (const FunctionProtoType *fproto - = dyn_cast<FunctionProtoType>(funcType.IgnoreParens())) { - for (const auto &I : fproto->param_types()) - if (isTopLevelBlockPointerType(I)) { - // All the args are checked/rewritten. Don't call twice! - RewriteBlockPointerDecl(D); - break; - } - } -} - -void RewriteModernObjC::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) { - const PointerType *PT = funcType->getAs<PointerType>(); - if (PT && PointerTypeTakesAnyBlockArguments(funcType)) - RewriteBlocksInFunctionProtoType(PT->getPointeeType(), ND); -} - -static bool IsHeaderFile(const std::string &Filename) { - std::string::size_type DotPos = Filename.rfind('.'); - - if (DotPos == std::string::npos) { - // no file extension - return false; - } - - std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end()); - // C header: .h - // C++ header: .hh or .H; - return Ext == "h" || Ext == "hh" || Ext == "H"; -} - -RewriteModernObjC::RewriteModernObjC(std::string inFile, raw_ostream* OS, - DiagnosticsEngine &D, const LangOptions &LOpts, - bool silenceMacroWarn, - bool LineInfo) - : Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS), - SilenceRewriteMacroWarning(silenceMacroWarn), GenerateLineInfo(LineInfo) { - IsHeader = IsHeaderFile(inFile); - RewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning, - "rewriting sub-expression within a macro (may not be correct)"); - // FIXME. This should be an error. But if block is not called, it is OK. And it - // may break including some headers. - GlobalBlockRewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning, - "rewriting block literal declared in global scope is not implemented"); - - TryFinallyContainsReturnDiag = Diags.getCustomDiagID( - DiagnosticsEngine::Warning, - "rewriter doesn't support user-specified control flow semantics " - "for @try/@finally (code may not execute properly)"); -} - -ASTConsumer *clang::CreateModernObjCRewriter(const std::string& InFile, - raw_ostream* OS, - DiagnosticsEngine &Diags, - const LangOptions &LOpts, - bool SilenceRewriteMacroWarning, - bool LineInfo) { - return new RewriteModernObjC(InFile, OS, Diags, LOpts, - SilenceRewriteMacroWarning, LineInfo); -} - -void RewriteModernObjC::InitializeCommon(ASTContext &context) { - Context = &context; - SM = &Context->getSourceManager(); - TUDecl = Context->getTranslationUnitDecl(); - MsgSendFunctionDecl = nullptr; - MsgSendSuperFunctionDecl = nullptr; - MsgSendStretFunctionDecl = nullptr; - MsgSendSuperStretFunctionDecl = nullptr; - MsgSendFpretFunctionDecl = nullptr; - GetClassFunctionDecl = nullptr; - GetMetaClassFunctionDecl = nullptr; - GetSuperClassFunctionDecl = nullptr; - SelGetUidFunctionDecl = nullptr; - CFStringFunctionDecl = nullptr; - ConstantStringClassReference = nullptr; - NSStringRecord = nullptr; - CurMethodDef = nullptr; - CurFunctionDef = nullptr; - GlobalVarDecl = nullptr; - GlobalConstructionExp = nullptr; - SuperStructDecl = nullptr; - ProtocolTypeDecl = nullptr; - ConstantStringDecl = nullptr; - BcLabelCount = 0; - SuperConstructorFunctionDecl = nullptr; - NumObjCStringLiterals = 0; - PropParentMap = nullptr; - CurrentBody = nullptr; - DisableReplaceStmt = false; - objc_impl_method = false; - - // Get the ID and start/end of the main file. - MainFileID = SM->getMainFileID(); - const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID); - MainFileStart = MainBuf->getBufferStart(); - MainFileEnd = MainBuf->getBufferEnd(); - - Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOpts()); -} - -//===----------------------------------------------------------------------===// -// Top Level Driver Code -//===----------------------------------------------------------------------===// - -void RewriteModernObjC::HandleTopLevelSingleDecl(Decl *D) { - if (Diags.hasErrorOccurred()) - return; - - // Two cases: either the decl could be in the main file, or it could be in a - // #included file. If the former, rewrite it now. If the later, check to see - // if we rewrote the #include/#import. - SourceLocation Loc = D->getLocation(); - Loc = SM->getExpansionLoc(Loc); - - // If this is for a builtin, ignore it. - if (Loc.isInvalid()) return; - - // Look for built-in declarations that we need to refer during the rewrite. - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - RewriteFunctionDecl(FD); - } else if (VarDecl *FVD = dyn_cast<VarDecl>(D)) { - // declared in <Foundation/NSString.h> - if (FVD->getName() == "_NSConstantStringClassReference") { - ConstantStringClassReference = FVD; - return; - } - } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) { - RewriteCategoryDecl(CD); - } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) { - if (PD->isThisDeclarationADefinition()) - RewriteProtocolDecl(PD); - } else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) { - // FIXME. This will not work in all situations and leaving it out - // is harmless. - // RewriteLinkageSpec(LSD); - - // Recurse into linkage specifications - for (DeclContext::decl_iterator DI = LSD->decls_begin(), - DIEnd = LSD->decls_end(); - DI != DIEnd; ) { - if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>((*DI))) { - if (!IFace->isThisDeclarationADefinition()) { - SmallVector<Decl *, 8> DG; - SourceLocation StartLoc = IFace->getLocStart(); - do { - if (isa<ObjCInterfaceDecl>(*DI) && - !cast<ObjCInterfaceDecl>(*DI)->isThisDeclarationADefinition() && - StartLoc == (*DI)->getLocStart()) - DG.push_back(*DI); - else - break; - - ++DI; - } while (DI != DIEnd); - RewriteForwardClassDecl(DG); - continue; - } - else { - // Keep track of all interface declarations seen. - ObjCInterfacesSeen.push_back(IFace); - ++DI; - continue; - } - } - - if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>((*DI))) { - if (!Proto->isThisDeclarationADefinition()) { - SmallVector<Decl *, 8> DG; - SourceLocation StartLoc = Proto->getLocStart(); - do { - if (isa<ObjCProtocolDecl>(*DI) && - !cast<ObjCProtocolDecl>(*DI)->isThisDeclarationADefinition() && - StartLoc == (*DI)->getLocStart()) - DG.push_back(*DI); - else - break; - - ++DI; - } while (DI != DIEnd); - RewriteForwardProtocolDecl(DG); - continue; - } - } - - HandleTopLevelSingleDecl(*DI); - ++DI; - } - } - // If we have a decl in the main file, see if we should rewrite it. - if (SM->isWrittenInMainFile(Loc)) - return HandleDeclInMainFile(D); -} - -//===----------------------------------------------------------------------===// -// Syntactic (non-AST) Rewriting Code -//===----------------------------------------------------------------------===// - -void RewriteModernObjC::RewriteInclude() { - SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID); - StringRef MainBuf = SM->getBufferData(MainFileID); - const char *MainBufStart = MainBuf.begin(); - const char *MainBufEnd = MainBuf.end(); - size_t ImportLen = strlen("import"); - - // Loop over the whole file, looking for includes. - for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) { - if (*BufPtr == '#') { - if (++BufPtr == MainBufEnd) - return; - while (*BufPtr == ' ' || *BufPtr == '\t') - if (++BufPtr == MainBufEnd) - return; - if (!strncmp(BufPtr, "import", ImportLen)) { - // replace import with include - SourceLocation ImportLoc = - LocStart.getLocWithOffset(BufPtr-MainBufStart); - ReplaceText(ImportLoc, ImportLen, "include"); - BufPtr += ImportLen; - } - } - } -} - -static void WriteInternalIvarName(const ObjCInterfaceDecl *IDecl, - ObjCIvarDecl *IvarDecl, std::string &Result) { - Result += "OBJC_IVAR_$_"; - Result += IDecl->getName(); - Result += "$"; - Result += IvarDecl->getName(); -} - -std::string -RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) { - const ObjCInterfaceDecl *ClassDecl = D->getContainingInterface(); - - // Build name of symbol holding ivar offset. - std::string IvarOffsetName; - if (D->isBitField()) - ObjCIvarBitfieldGroupOffset(D, IvarOffsetName); - else - WriteInternalIvarName(ClassDecl, D, IvarOffsetName); - - - std::string S = "(*("; - QualType IvarT = D->getType(); - if (D->isBitField()) - IvarT = GetGroupRecordTypeForObjCIvarBitfield(D); - - if (!isa<TypedefType>(IvarT) && IvarT->isRecordType()) { - RecordDecl *RD = IvarT->getAs<RecordType>()->getDecl(); - RD = RD->getDefinition(); - if (RD && !RD->getDeclName().getAsIdentifierInfo()) { - // decltype(((Foo_IMPL*)0)->bar) * - ObjCContainerDecl *CDecl = - dyn_cast<ObjCContainerDecl>(D->getDeclContext()); - // ivar in class extensions requires special treatment. - if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) - CDecl = CatDecl->getClassInterface(); - std::string RecName = CDecl->getName(); - RecName += "_IMPL"; - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get(RecName.c_str())); - QualType PtrStructIMPL = Context->getPointerType(Context->getTagDeclType(RD)); - unsigned UnsignedIntSize = - static_cast<unsigned>(Context->getTypeSize(Context->UnsignedIntTy)); - Expr *Zero = IntegerLiteral::Create(*Context, - llvm::APInt(UnsignedIntSize, 0), - Context->UnsignedIntTy, SourceLocation()); - Zero = NoTypeInfoCStyleCastExpr(Context, PtrStructIMPL, CK_BitCast, Zero); - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - Zero); - FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), - SourceLocation(), - &Context->Idents.get(D->getNameAsString()), - IvarT, nullptr, - /*BitWidth=*/nullptr, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), - FD->getType(), VK_LValue, - OK_Ordinary); - IvarT = Context->getDecltypeType(ME, ME->getType()); - } - } - convertObjCTypeToCStyleType(IvarT); - QualType castT = Context->getPointerType(IvarT); - std::string TypeString(castT.getAsString(Context->getPrintingPolicy())); - S += TypeString; - S += ")"; - - // ((char *)self + IVAR_OFFSET_SYMBOL_NAME) - S += "((char *)self + "; - S += IvarOffsetName; - S += "))"; - if (D->isBitField()) { - S += "."; - S += D->getNameAsString(); - } - ReferencedIvars[const_cast<ObjCInterfaceDecl *>(ClassDecl)].insert(D); - return S; -} - -/// mustSynthesizeSetterGetterMethod - returns true if setter or getter has not -/// been found in the class implementation. In this case, it must be synthesized. -static bool mustSynthesizeSetterGetterMethod(ObjCImplementationDecl *IMP, - ObjCPropertyDecl *PD, - bool getter) { - return getter ? !IMP->getInstanceMethod(PD->getGetterName()) - : !IMP->getInstanceMethod(PD->getSetterName()); - -} - -void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, - ObjCImplementationDecl *IMD, - ObjCCategoryImplDecl *CID) { - static bool objcGetPropertyDefined = false; - static bool objcSetPropertyDefined = false; - SourceLocation startGetterSetterLoc; - - if (PID->getLocStart().isValid()) { - SourceLocation startLoc = PID->getLocStart(); - InsertText(startLoc, "// "); - const char *startBuf = SM->getCharacterData(startLoc); - assert((*startBuf == '@') && "bogus @synthesize location"); - const char *semiBuf = strchr(startBuf, ';'); - assert((*semiBuf == ';') && "@synthesize: can't find ';'"); - startGetterSetterLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1); - } - else - startGetterSetterLoc = IMD ? IMD->getLocEnd() : CID->getLocEnd(); - - if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - return; // FIXME: is this correct? - - // Generate the 'getter' function. - ObjCPropertyDecl *PD = PID->getPropertyDecl(); - ObjCIvarDecl *OID = PID->getPropertyIvarDecl(); - assert(IMD && OID && "Synthesized ivars must be attached to @implementation"); - - unsigned Attributes = PD->getPropertyAttributes(); - if (mustSynthesizeSetterGetterMethod(IMD, PD, true /*getter*/)) { - bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) && - (Attributes & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy)); - std::string Getr; - if (GenGetProperty && !objcGetPropertyDefined) { - objcGetPropertyDefined = true; - // FIXME. Is this attribute correct in all cases? - Getr = "\nextern \"C\" __declspec(dllimport) " - "id objc_getProperty(id, SEL, long, bool);\n"; - } - RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getGetterMethodDecl(), Getr); - Getr += "{ "; - // Synthesize an explicit cast to gain access to the ivar. - // See objc-act.c:objc_synthesize_new_getter() for details. - if (GenGetProperty) { - // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) - Getr += "typedef "; - const FunctionType *FPRetType = nullptr; - RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr, - FPRetType); - Getr += " _TYPE"; - if (FPRetType) { - Getr += ")"; // close the precedence "scope" for "*". - - // Now, emit the argument types (if any). - if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)){ - Getr += "("; - for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { - if (i) Getr += ", "; - std::string ParamStr = - FT->getParamType(i).getAsString(Context->getPrintingPolicy()); - Getr += ParamStr; - } - if (FT->isVariadic()) { - if (FT->getNumParams()) - Getr += ", "; - Getr += "..."; - } - Getr += ")"; - } else - Getr += "()"; - } - Getr += ";\n"; - Getr += "return (_TYPE)"; - Getr += "objc_getProperty(self, _cmd, "; - RewriteIvarOffsetComputation(OID, Getr); - Getr += ", 1)"; - } - else - Getr += "return " + getIvarAccessString(OID); - Getr += "; }"; - InsertText(startGetterSetterLoc, Getr); - } - - if (PD->isReadOnly() || - !mustSynthesizeSetterGetterMethod(IMD, PD, false /*setter*/)) - return; - - // Generate the 'setter' function. - std::string Setr; - bool GenSetProperty = Attributes & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy); - if (GenSetProperty && !objcSetPropertyDefined) { - objcSetPropertyDefined = true; - // FIXME. Is this attribute correct in all cases? - Setr = "\nextern \"C\" __declspec(dllimport) " - "void objc_setProperty (id, SEL, long, id, bool, bool);\n"; - } - - RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getSetterMethodDecl(), Setr); - Setr += "{ "; - // Synthesize an explicit cast to initialize the ivar. - // See objc-act.c:objc_synthesize_new_setter() for details. - if (GenSetProperty) { - Setr += "objc_setProperty (self, _cmd, "; - RewriteIvarOffsetComputation(OID, Setr); - Setr += ", (id)"; - Setr += PD->getName(); - Setr += ", "; - if (Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) - Setr += "0, "; - else - Setr += "1, "; - if (Attributes & ObjCPropertyDecl::OBJC_PR_copy) - Setr += "1)"; - else - Setr += "0)"; - } - else { - Setr += getIvarAccessString(OID) + " = "; - Setr += PD->getName(); - } - Setr += "; }\n"; - InsertText(startGetterSetterLoc, Setr); -} - -static void RewriteOneForwardClassDecl(ObjCInterfaceDecl *ForwardDecl, - std::string &typedefString) { - typedefString += "\n#ifndef _REWRITER_typedef_"; - typedefString += ForwardDecl->getNameAsString(); - typedefString += "\n"; - typedefString += "#define _REWRITER_typedef_"; - typedefString += ForwardDecl->getNameAsString(); - typedefString += "\n"; - typedefString += "typedef struct objc_object "; - typedefString += ForwardDecl->getNameAsString(); - // typedef struct { } _objc_exc_Classname; - typedefString += ";\ntypedef struct {} _objc_exc_"; - typedefString += ForwardDecl->getNameAsString(); - typedefString += ";\n#endif\n"; -} - -void RewriteModernObjC::RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl, - const std::string &typedefString) { - SourceLocation startLoc = ClassDecl->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - const char *semiPtr = strchr(startBuf, ';'); - // Replace the @class with typedefs corresponding to the classes. - ReplaceText(startLoc, semiPtr-startBuf+1, typedefString); -} - -void RewriteModernObjC::RewriteForwardClassDecl(DeclGroupRef D) { - std::string typedefString; - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { - if (ObjCInterfaceDecl *ForwardDecl = dyn_cast<ObjCInterfaceDecl>(*I)) { - if (I == D.begin()) { - // Translate to typedef's that forward reference structs with the same name - // as the class. As a convenience, we include the original declaration - // as a comment. - typedefString += "// @class "; - typedefString += ForwardDecl->getNameAsString(); - typedefString += ";"; - } - RewriteOneForwardClassDecl(ForwardDecl, typedefString); - } - else - HandleTopLevelSingleDecl(*I); - } - DeclGroupRef::iterator I = D.begin(); - RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(*I), typedefString); -} - -void RewriteModernObjC::RewriteForwardClassDecl( - const SmallVectorImpl<Decl *> &D) { - std::string typedefString; - for (unsigned i = 0; i < D.size(); i++) { - ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(D[i]); - if (i == 0) { - typedefString += "// @class "; - typedefString += ForwardDecl->getNameAsString(); - typedefString += ";"; - } - RewriteOneForwardClassDecl(ForwardDecl, typedefString); - } - RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(D[0]), typedefString); -} - -void RewriteModernObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { - // When method is a synthesized one, such as a getter/setter there is - // nothing to rewrite. - if (Method->isImplicit()) - return; - SourceLocation LocStart = Method->getLocStart(); - SourceLocation LocEnd = Method->getLocEnd(); - - if (SM->getExpansionLineNumber(LocEnd) > - SM->getExpansionLineNumber(LocStart)) { - InsertText(LocStart, "#if 0\n"); - ReplaceText(LocEnd, 1, ";\n#endif\n"); - } else { - InsertText(LocStart, "// "); - } -} - -void RewriteModernObjC::RewriteProperty(ObjCPropertyDecl *prop) { - SourceLocation Loc = prop->getAtLoc(); - - ReplaceText(Loc, 0, "// "); - // FIXME: handle properties that are declared across multiple lines. -} - -void RewriteModernObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { - SourceLocation LocStart = CatDecl->getLocStart(); - - // FIXME: handle category headers that are declared across multiple lines. - if (CatDecl->getIvarRBraceLoc().isValid()) { - ReplaceText(LocStart, 1, "/** "); - ReplaceText(CatDecl->getIvarRBraceLoc(), 1, "**/ "); - } - else { - ReplaceText(LocStart, 0, "// "); - } - - for (auto *I : CatDecl->properties()) - RewriteProperty(I); - - for (auto *I : CatDecl->instance_methods()) - RewriteMethodDeclaration(I); - for (auto *I : CatDecl->class_methods()) - RewriteMethodDeclaration(I); - - // Lastly, comment out the @end. - ReplaceText(CatDecl->getAtEndRange().getBegin(), - strlen("@end"), "/* @end */\n"); -} - -void RewriteModernObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { - SourceLocation LocStart = PDecl->getLocStart(); - assert(PDecl->isThisDeclarationADefinition()); - - // FIXME: handle protocol headers that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); - - for (auto *I : PDecl->instance_methods()) - RewriteMethodDeclaration(I); - for (auto *I : PDecl->class_methods()) - RewriteMethodDeclaration(I); - for (auto *I : PDecl->properties()) - RewriteProperty(I); - - // Lastly, comment out the @end. - SourceLocation LocEnd = PDecl->getAtEndRange().getBegin(); - ReplaceText(LocEnd, strlen("@end"), "/* @end */\n"); - - // Must comment out @optional/@required - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - for (const char *p = startBuf; p < endBuf; p++) { - if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) { - SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); - ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */"); - - } - else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) { - SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); - ReplaceText(OptionalLoc, strlen("@required"), "/* @required */"); - - } - } -} - -void RewriteModernObjC::RewriteForwardProtocolDecl(DeclGroupRef D) { - SourceLocation LocStart = (*D.begin())->getLocStart(); - if (LocStart.isInvalid()) - llvm_unreachable("Invalid SourceLocation"); - // FIXME: handle forward protocol that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); -} - -void -RewriteModernObjC::RewriteForwardProtocolDecl(const SmallVectorImpl<Decl *> &DG) { - SourceLocation LocStart = DG[0]->getLocStart(); - if (LocStart.isInvalid()) - llvm_unreachable("Invalid SourceLocation"); - // FIXME: handle forward protocol that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); -} - -void -RewriteModernObjC::RewriteLinkageSpec(LinkageSpecDecl *LSD) { - SourceLocation LocStart = LSD->getExternLoc(); - if (LocStart.isInvalid()) - llvm_unreachable("Invalid extern SourceLocation"); - - ReplaceText(LocStart, 0, "// "); - if (!LSD->hasBraces()) - return; - // FIXME. We don't rewrite well if '{' is not on same line as 'extern'. - SourceLocation LocRBrace = LSD->getRBraceLoc(); - if (LocRBrace.isInvalid()) - llvm_unreachable("Invalid rbrace SourceLocation"); - ReplaceText(LocRBrace, 0, "// "); -} - -void RewriteModernObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr, - const FunctionType *&FPRetType) { - if (T->isObjCQualifiedIdType()) - ResultStr += "id"; - else if (T->isFunctionPointerType() || - T->isBlockPointerType()) { - // needs special handling, since pointer-to-functions have special - // syntax (where a decaration models use). - QualType retType = T; - QualType PointeeTy; - if (const PointerType* PT = retType->getAs<PointerType>()) - PointeeTy = PT->getPointeeType(); - else if (const BlockPointerType *BPT = retType->getAs<BlockPointerType>()) - PointeeTy = BPT->getPointeeType(); - if ((FPRetType = PointeeTy->getAs<FunctionType>())) { - ResultStr += - FPRetType->getReturnType().getAsString(Context->getPrintingPolicy()); - ResultStr += "(*"; - } - } else - ResultStr += T.getAsString(Context->getPrintingPolicy()); -} - -void RewriteModernObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, - ObjCMethodDecl *OMD, - std::string &ResultStr) { - //fprintf(stderr,"In RewriteObjCMethodDecl\n"); - const FunctionType *FPRetType = nullptr; - ResultStr += "\nstatic "; - RewriteTypeIntoString(OMD->getReturnType(), ResultStr, FPRetType); - ResultStr += " "; - - // Unique method name - std::string NameStr; - - if (OMD->isInstanceMethod()) - NameStr += "_I_"; - else - NameStr += "_C_"; - - NameStr += IDecl->getNameAsString(); - NameStr += "_"; - - if (ObjCCategoryImplDecl *CID = - dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) { - NameStr += CID->getNameAsString(); - NameStr += "_"; - } - // Append selector names, replacing ':' with '_' - { - std::string selString = OMD->getSelector().getAsString(); - int len = selString.size(); - for (int i = 0; i < len; i++) - if (selString[i] == ':') - selString[i] = '_'; - NameStr += selString; - } - // Remember this name for metadata emission - MethodInternalNames[OMD] = NameStr; - ResultStr += NameStr; - - // Rewrite arguments - ResultStr += "("; - - // invisible arguments - if (OMD->isInstanceMethod()) { - QualType selfTy = Context->getObjCInterfaceType(IDecl); - selfTy = Context->getPointerType(selfTy); - if (!LangOpts.MicrosoftExt) { - if (ObjCSynthesizedStructs.count(const_cast<ObjCInterfaceDecl*>(IDecl))) - ResultStr += "struct "; - } - // When rewriting for Microsoft, explicitly omit the structure name. - ResultStr += IDecl->getNameAsString(); - ResultStr += " *"; - } - else - ResultStr += Context->getObjCClassType().getAsString( - Context->getPrintingPolicy()); - - ResultStr += " self, "; - ResultStr += Context->getObjCSelType().getAsString(Context->getPrintingPolicy()); - ResultStr += " _cmd"; - - // Method arguments. - for (const auto *PDecl : OMD->params()) { - ResultStr += ", "; - if (PDecl->getType()->isObjCQualifiedIdType()) { - ResultStr += "id "; - ResultStr += PDecl->getNameAsString(); - } else { - std::string Name = PDecl->getNameAsString(); - QualType QT = PDecl->getType(); - // Make sure we convert "t (^)(...)" to "t (*)(...)". - (void)convertBlockPointerToFunctionPointer(QT); - QT.getAsStringInternal(Name, Context->getPrintingPolicy()); - ResultStr += Name; - } - } - if (OMD->isVariadic()) - ResultStr += ", ..."; - ResultStr += ") "; - - if (FPRetType) { - ResultStr += ")"; // close the precedence "scope" for "*". - - // Now, emit the argument types (if any). - if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)) { - ResultStr += "("; - for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { - if (i) ResultStr += ", "; - std::string ParamStr = - FT->getParamType(i).getAsString(Context->getPrintingPolicy()); - ResultStr += ParamStr; - } - if (FT->isVariadic()) { - if (FT->getNumParams()) - ResultStr += ", "; - ResultStr += "..."; - } - ResultStr += ")"; - } else { - ResultStr += "()"; - } - } -} -void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) { - ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID); - ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID); - - if (IMD) { - if (IMD->getIvarRBraceLoc().isValid()) { - ReplaceText(IMD->getLocStart(), 1, "/** "); - ReplaceText(IMD->getIvarRBraceLoc(), 1, "**/ "); - } - else { - InsertText(IMD->getLocStart(), "// "); - } - } - else - InsertText(CID->getLocStart(), "// "); - - for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) { - std::string ResultStr; - RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); - SourceLocation LocStart = OMD->getLocStart(); - SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - ReplaceText(LocStart, endBuf-startBuf, ResultStr); - } - - for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) { - std::string ResultStr; - RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); - SourceLocation LocStart = OMD->getLocStart(); - SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - ReplaceText(LocStart, endBuf-startBuf, ResultStr); - } - for (auto *I : IMD ? IMD->property_impls() : CID->property_impls()) - RewritePropertyImplDecl(I, IMD, CID); - - InsertText(IMD ? IMD->getLocEnd() : CID->getLocEnd(), "// "); -} - -void RewriteModernObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { - // Do not synthesize more than once. - if (ObjCSynthesizedStructs.count(ClassDecl)) - return; - // Make sure super class's are written before current class is written. - ObjCInterfaceDecl *SuperClass = ClassDecl->getSuperClass(); - while (SuperClass) { - RewriteInterfaceDecl(SuperClass); - SuperClass = SuperClass->getSuperClass(); - } - std::string ResultStr; - if (!ObjCWrittenInterfaces.count(ClassDecl->getCanonicalDecl())) { - // we haven't seen a forward decl - generate a typedef. - RewriteOneForwardClassDecl(ClassDecl, ResultStr); - RewriteIvarOffsetSymbols(ClassDecl, ResultStr); - - RewriteObjCInternalStruct(ClassDecl, ResultStr); - // Mark this typedef as having been written into its c++ equivalent. - ObjCWrittenInterfaces.insert(ClassDecl->getCanonicalDecl()); - - for (auto *I : ClassDecl->properties()) - RewriteProperty(I); - for (auto *I : ClassDecl->instance_methods()) - RewriteMethodDeclaration(I); - for (auto *I : ClassDecl->class_methods()) - RewriteMethodDeclaration(I); - - // Lastly, comment out the @end. - ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"), - "/* @end */\n"); - } -} - -Stmt *RewriteModernObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *PseudoOp) { - SourceRange OldRange = PseudoOp->getSourceRange(); - - // We just magically know some things about the structure of this - // expression. - ObjCMessageExpr *OldMsg = - cast<ObjCMessageExpr>(PseudoOp->getSemanticExpr( - PseudoOp->getNumSemanticExprs() - 1)); - - // Because the rewriter doesn't allow us to rewrite rewritten code, - // we need to suppress rewriting the sub-statements. - Expr *Base; - SmallVector<Expr*, 2> Args; - { - DisableReplaceStmtScope S(*this); - - // Rebuild the base expression if we have one. - Base = nullptr; - if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) { - Base = OldMsg->getInstanceReceiver(); - Base = cast<OpaqueValueExpr>(Base)->getSourceExpr(); - Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base)); - } - - unsigned numArgs = OldMsg->getNumArgs(); - for (unsigned i = 0; i < numArgs; i++) { - Expr *Arg = OldMsg->getArg(i); - if (isa<OpaqueValueExpr>(Arg)) - Arg = cast<OpaqueValueExpr>(Arg)->getSourceExpr(); - Arg = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Arg)); - Args.push_back(Arg); - } - } - - // TODO: avoid this copy. - SmallVector<SourceLocation, 1> SelLocs; - OldMsg->getSelectorLocs(SelLocs); - - ObjCMessageExpr *NewMsg = nullptr; - switch (OldMsg->getReceiverKind()) { - case ObjCMessageExpr::Class: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getClassReceiverTypeInfo(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::Instance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - Base, - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::SuperClass: - case ObjCMessageExpr::SuperInstance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getSuperLoc(), - OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance, - OldMsg->getSuperType(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - } - - Stmt *Replacement = SynthMessageExpr(NewMsg); - ReplaceStmtWithRange(PseudoOp, Replacement, OldRange); - return Replacement; -} - -Stmt *RewriteModernObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *PseudoOp) { - SourceRange OldRange = PseudoOp->getSourceRange(); - - // We just magically know some things about the structure of this - // expression. - ObjCMessageExpr *OldMsg = - cast<ObjCMessageExpr>(PseudoOp->getResultExpr()->IgnoreImplicit()); - - // Because the rewriter doesn't allow us to rewrite rewritten code, - // we need to suppress rewriting the sub-statements. - Expr *Base = nullptr; - SmallVector<Expr*, 1> Args; - { - DisableReplaceStmtScope S(*this); - // Rebuild the base expression if we have one. - if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) { - Base = OldMsg->getInstanceReceiver(); - Base = cast<OpaqueValueExpr>(Base)->getSourceExpr(); - Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base)); - } - unsigned numArgs = OldMsg->getNumArgs(); - for (unsigned i = 0; i < numArgs; i++) { - Expr *Arg = OldMsg->getArg(i); - if (isa<OpaqueValueExpr>(Arg)) - Arg = cast<OpaqueValueExpr>(Arg)->getSourceExpr(); - Arg = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Arg)); - Args.push_back(Arg); - } - } - - // Intentionally empty. - SmallVector<SourceLocation, 1> SelLocs; - - ObjCMessageExpr *NewMsg = nullptr; - switch (OldMsg->getReceiverKind()) { - case ObjCMessageExpr::Class: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getClassReceiverTypeInfo(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::Instance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - Base, - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::SuperClass: - case ObjCMessageExpr::SuperInstance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getSuperLoc(), - OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance, - OldMsg->getSuperType(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - } - - Stmt *Replacement = SynthMessageExpr(NewMsg); - ReplaceStmtWithRange(PseudoOp, Replacement, OldRange); - return Replacement; -} - -/// SynthCountByEnumWithState - To print: -/// ((NSUInteger (*) -/// (id, SEL, struct __objcFastEnumerationState *, id *, NSUInteger)) -/// (void *)objc_msgSend)((id)l_collection, -/// sel_registerName( -/// "countByEnumeratingWithState:objects:count:"), -/// &enumState, -/// (id *)__rw_items, (NSUInteger)16) -/// -void RewriteModernObjC::SynthCountByEnumWithState(std::string &buf) { - buf += "((_WIN_NSUInteger (*) (id, SEL, struct __objcFastEnumerationState *, " - "id *, _WIN_NSUInteger))(void *)objc_msgSend)"; - buf += "\n\t\t"; - buf += "((id)l_collection,\n\t\t"; - buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),"; - buf += "\n\t\t"; - buf += "&enumState, " - "(id *)__rw_items, (_WIN_NSUInteger)16)"; -} - -/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach -/// statement to exit to its outer synthesized loop. -/// -Stmt *RewriteModernObjC::RewriteBreakStmt(BreakStmt *S) { - if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back())) - return S; - // replace break with goto __break_label - std::string buf; - - SourceLocation startLoc = S->getLocStart(); - buf = "goto __break_label_"; - buf += utostr(ObjCBcLabelNo.back()); - ReplaceText(startLoc, strlen("break"), buf); - - return nullptr; -} - -void RewriteModernObjC::ConvertSourceLocationToLineDirective( - SourceLocation Loc, - std::string &LineString) { - if (Loc.isFileID() && GenerateLineInfo) { - LineString += "\n#line "; - PresumedLoc PLoc = SM->getPresumedLoc(Loc); - LineString += utostr(PLoc.getLine()); - LineString += " \""; - LineString += Lexer::Stringify(PLoc.getFilename()); - LineString += "\"\n"; - } -} - -/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach -/// statement to continue with its inner synthesized loop. -/// -Stmt *RewriteModernObjC::RewriteContinueStmt(ContinueStmt *S) { - if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back())) - return S; - // replace continue with goto __continue_label - std::string buf; - - SourceLocation startLoc = S->getLocStart(); - buf = "goto __continue_label_"; - buf += utostr(ObjCBcLabelNo.back()); - ReplaceText(startLoc, strlen("continue"), buf); - - return nullptr; -} - -/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement. -/// It rewrites: -/// for ( type elem in collection) { stmts; } - -/// Into: -/// { -/// type elem; -/// struct __objcFastEnumerationState enumState = { 0 }; -/// id __rw_items[16]; -/// id l_collection = (id)collection; -/// NSUInteger limit = [l_collection countByEnumeratingWithState:&enumState -/// objects:__rw_items count:16]; -/// if (limit) { -/// unsigned long startMutations = *enumState.mutationsPtr; -/// do { -/// unsigned long counter = 0; -/// do { -/// if (startMutations != *enumState.mutationsPtr) -/// objc_enumerationMutation(l_collection); -/// elem = (type)enumState.itemsPtr[counter++]; -/// stmts; -/// __continue_label: ; -/// } while (counter < limit); -/// } while ((limit = [l_collection countByEnumeratingWithState:&enumState -/// objects:__rw_items count:16])); -/// elem = nil; -/// __break_label: ; -/// } -/// else -/// elem = nil; -/// } -/// -Stmt *RewriteModernObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, - SourceLocation OrigEnd) { - assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty"); - assert(isa<ObjCForCollectionStmt>(Stmts.back()) && - "ObjCForCollectionStmt Statement stack mismatch"); - assert(!ObjCBcLabelNo.empty() && - "ObjCForCollectionStmt - Label No stack empty"); - - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - StringRef elementName; - std::string elementTypeAsString; - std::string buf; - // line directive first. - SourceLocation ForEachLoc = S->getForLoc(); - ConvertSourceLocationToLineDirective(ForEachLoc, buf); - buf += "{\n\t"; - if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) { - // type elem; - NamedDecl* D = cast<NamedDecl>(DS->getSingleDecl()); - QualType ElementType = cast<ValueDecl>(D)->getType(); - if (ElementType->isObjCQualifiedIdType() || - ElementType->isObjCQualifiedInterfaceType()) - // Simply use 'id' for all qualified types. - elementTypeAsString = "id"; - else - elementTypeAsString = ElementType.getAsString(Context->getPrintingPolicy()); - buf += elementTypeAsString; - buf += " "; - elementName = D->getName(); - buf += elementName; - buf += ";\n\t"; - } - else { - DeclRefExpr *DR = cast<DeclRefExpr>(S->getElement()); - elementName = DR->getDecl()->getName(); - ValueDecl *VD = cast<ValueDecl>(DR->getDecl()); - if (VD->getType()->isObjCQualifiedIdType() || - VD->getType()->isObjCQualifiedInterfaceType()) - // Simply use 'id' for all qualified types. - elementTypeAsString = "id"; - else - elementTypeAsString = VD->getType().getAsString(Context->getPrintingPolicy()); - } - - // struct __objcFastEnumerationState enumState = { 0 }; - buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t"; - // id __rw_items[16]; - buf += "id __rw_items[16];\n\t"; - // id l_collection = (id) - buf += "id l_collection = (id)"; - // Find start location of 'collection' the hard way! - const char *startCollectionBuf = startBuf; - startCollectionBuf += 3; // skip 'for' - startCollectionBuf = strchr(startCollectionBuf, '('); - startCollectionBuf++; // skip '(' - // find 'in' and skip it. - while (*startCollectionBuf != ' ' || - *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' || - (*(startCollectionBuf+3) != ' ' && - *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '(')) - startCollectionBuf++; - startCollectionBuf += 3; - - // Replace: "for (type element in" with string constructed thus far. - ReplaceText(startLoc, startCollectionBuf - startBuf, buf); - // Replace ')' in for '(' type elem in collection ')' with ';' - SourceLocation rightParenLoc = S->getRParenLoc(); - const char *rparenBuf = SM->getCharacterData(rightParenLoc); - SourceLocation lparenLoc = startLoc.getLocWithOffset(rparenBuf-startBuf); - buf = ";\n\t"; - - // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState - // objects:__rw_items count:16]; - // which is synthesized into: - // NSUInteger limit = - // ((NSUInteger (*) - // (id, SEL, struct __objcFastEnumerationState *, id *, NSUInteger)) - // (void *)objc_msgSend)((id)l_collection, - // sel_registerName( - // "countByEnumeratingWithState:objects:count:"), - // (struct __objcFastEnumerationState *)&state, - // (id *)__rw_items, (NSUInteger)16); - buf += "_WIN_NSUInteger limit =\n\t\t"; - SynthCountByEnumWithState(buf); - buf += ";\n\t"; - /// if (limit) { - /// unsigned long startMutations = *enumState.mutationsPtr; - /// do { - /// unsigned long counter = 0; - /// do { - /// if (startMutations != *enumState.mutationsPtr) - /// objc_enumerationMutation(l_collection); - /// elem = (type)enumState.itemsPtr[counter++]; - buf += "if (limit) {\n\t"; - buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t"; - buf += "do {\n\t\t"; - buf += "unsigned long counter = 0;\n\t\t"; - buf += "do {\n\t\t\t"; - buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t"; - buf += "objc_enumerationMutation(l_collection);\n\t\t\t"; - buf += elementName; - buf += " = ("; - buf += elementTypeAsString; - buf += ")enumState.itemsPtr[counter++];"; - // Replace ')' in for '(' type elem in collection ')' with all of these. - ReplaceText(lparenLoc, 1, buf); - - /// __continue_label: ; - /// } while (counter < limit); - /// } while ((limit = [l_collection countByEnumeratingWithState:&enumState - /// objects:__rw_items count:16])); - /// elem = nil; - /// __break_label: ; - /// } - /// else - /// elem = nil; - /// } - /// - buf = ";\n\t"; - buf += "__continue_label_"; - buf += utostr(ObjCBcLabelNo.back()); - buf += ": ;"; - buf += "\n\t\t"; - buf += "} while (counter < limit);\n\t"; - buf += "} while ((limit = "; - SynthCountByEnumWithState(buf); - buf += "));\n\t"; - buf += elementName; - buf += " = (("; - buf += elementTypeAsString; - buf += ")0);\n\t"; - buf += "__break_label_"; - buf += utostr(ObjCBcLabelNo.back()); - buf += ": ;\n\t"; - buf += "}\n\t"; - buf += "else\n\t\t"; - buf += elementName; - buf += " = (("; - buf += elementTypeAsString; - buf += ")0);\n\t"; - buf += "}\n"; - - // Insert all these *after* the statement body. - // FIXME: If this should support Obj-C++, support CXXTryStmt - if (isa<CompoundStmt>(S->getBody())) { - SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(1); - InsertText(endBodyLoc, buf); - } else { - /* Need to treat single statements specially. For example: - * - * for (A *a in b) if (stuff()) break; - * for (A *a in b) xxxyy; - * - * The following code simply scans ahead to the semi to find the actual end. - */ - const char *stmtBuf = SM->getCharacterData(OrigEnd); - const char *semiBuf = strchr(stmtBuf, ';'); - assert(semiBuf && "Can't find ';'"); - SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(semiBuf-stmtBuf+1); - InsertText(endBodyLoc, buf); - } - Stmts.pop_back(); - ObjCBcLabelNo.pop_back(); - return nullptr; -} - -static void Write_RethrowObject(std::string &buf) { - buf += "{ struct _FIN { _FIN(id reth) : rethrow(reth) {}\n"; - buf += "\t~_FIN() { if (rethrow) objc_exception_throw(rethrow); }\n"; - buf += "\tid rethrow;\n"; - buf += "\t} _fin_force_rethow(_rethrow);"; -} - -/// RewriteObjCSynchronizedStmt - -/// This routine rewrites @synchronized(expr) stmt; -/// into: -/// objc_sync_enter(expr); -/// @try stmt @finally { objc_sync_exit(expr); } -/// -Stmt *RewriteModernObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @synchronized location"); - - std::string buf; - SourceLocation SynchLoc = S->getAtSynchronizedLoc(); - ConvertSourceLocationToLineDirective(SynchLoc, buf); - buf += "{ id _rethrow = 0; id _sync_obj = (id)"; - - const char *lparenBuf = startBuf; - while (*lparenBuf != '(') lparenBuf++; - ReplaceText(startLoc, lparenBuf-startBuf+1, buf); - - buf = "; objc_sync_enter(_sync_obj);\n"; - buf += "try {\n\tstruct _SYNC_EXIT { _SYNC_EXIT(id arg) : sync_exit(arg) {}"; - buf += "\n\t~_SYNC_EXIT() {objc_sync_exit(sync_exit);}"; - buf += "\n\tid sync_exit;"; - buf += "\n\t} _sync_exit(_sync_obj);\n"; - - // We can't use S->getSynchExpr()->getLocEnd() to find the end location, since - // the sync expression is typically a message expression that's already - // been rewritten! (which implies the SourceLocation's are invalid). - SourceLocation RParenExprLoc = S->getSynchBody()->getLocStart(); - const char *RParenExprLocBuf = SM->getCharacterData(RParenExprLoc); - while (*RParenExprLocBuf != ')') RParenExprLocBuf--; - RParenExprLoc = startLoc.getLocWithOffset(RParenExprLocBuf-startBuf); - - SourceLocation LBranceLoc = S->getSynchBody()->getLocStart(); - const char *LBraceLocBuf = SM->getCharacterData(LBranceLoc); - assert (*LBraceLocBuf == '{'); - ReplaceText(RParenExprLoc, (LBraceLocBuf - SM->getCharacterData(RParenExprLoc) + 1), buf); - - SourceLocation startRBraceLoc = S->getSynchBody()->getLocEnd(); - assert((*SM->getCharacterData(startRBraceLoc) == '}') && - "bogus @synchronized block"); - - buf = "} catch (id e) {_rethrow = e;}\n"; - Write_RethrowObject(buf); - buf += "}\n"; - buf += "}\n"; - - ReplaceText(startRBraceLoc, 1, buf); - - return nullptr; -} - -void RewriteModernObjC::WarnAboutReturnGotoStmts(Stmt *S) -{ - // Perform a bottom up traversal of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) - WarnAboutReturnGotoStmts(*CI); - - if (isa<ReturnStmt>(S) || isa<GotoStmt>(S)) { - Diags.Report(Context->getFullLoc(S->getLocStart()), - TryFinallyContainsReturnDiag); - } - return; -} - -Stmt *RewriteModernObjC::RewriteObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { - SourceLocation startLoc = S->getAtLoc(); - ReplaceText(startLoc, strlen("@autoreleasepool"), "/* @autoreleasepool */"); - ReplaceText(S->getSubStmt()->getLocStart(), 1, - "{ __AtAutoreleasePool __autoreleasepool; "); - - return nullptr; -} - -Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { - ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt(); - bool noCatch = S->getNumCatchStmts() == 0; - std::string buf; - SourceLocation TryLocation = S->getAtTryLoc(); - ConvertSourceLocationToLineDirective(TryLocation, buf); - - if (finalStmt) { - if (noCatch) - buf += "{ id volatile _rethrow = 0;\n"; - else { - buf += "{ id volatile _rethrow = 0;\ntry {\n"; - } - } - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @try location"); - if (finalStmt) - ReplaceText(startLoc, 1, buf); - else - // @try -> try - ReplaceText(startLoc, 1, ""); - - for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { - ObjCAtCatchStmt *Catch = S->getCatchStmt(I); - VarDecl *catchDecl = Catch->getCatchParamDecl(); - - startLoc = Catch->getLocStart(); - bool AtRemoved = false; - if (catchDecl) { - QualType t = catchDecl->getType(); - if (const ObjCObjectPointerType *Ptr = t->getAs<ObjCObjectPointerType>()) { - // Should be a pointer to a class. - ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface(); - if (IDecl) { - std::string Result; - ConvertSourceLocationToLineDirective(Catch->getLocStart(), Result); - - startBuf = SM->getCharacterData(startLoc); - assert((*startBuf == '@') && "bogus @catch location"); - SourceLocation rParenLoc = Catch->getRParenLoc(); - const char *rParenBuf = SM->getCharacterData(rParenLoc); - - // _objc_exc_Foo *_e as argument to catch. - Result += "catch (_objc_exc_"; Result += IDecl->getNameAsString(); - Result += " *_"; Result += catchDecl->getNameAsString(); - Result += ")"; - ReplaceText(startLoc, rParenBuf-startBuf+1, Result); - // Foo *e = (Foo *)_e; - Result.clear(); - Result = "{ "; - Result += IDecl->getNameAsString(); - Result += " *"; Result += catchDecl->getNameAsString(); - Result += " = ("; Result += IDecl->getNameAsString(); Result += "*)"; - Result += "_"; Result += catchDecl->getNameAsString(); - - Result += "; "; - SourceLocation lBraceLoc = Catch->getCatchBody()->getLocStart(); - ReplaceText(lBraceLoc, 1, Result); - AtRemoved = true; - } - } - } - if (!AtRemoved) - // @catch -> catch - ReplaceText(startLoc, 1, ""); - - } - if (finalStmt) { - buf.clear(); - SourceLocation FinallyLoc = finalStmt->getLocStart(); - - if (noCatch) { - ConvertSourceLocationToLineDirective(FinallyLoc, buf); - buf += "catch (id e) {_rethrow = e;}\n"; - } - else { - buf += "}\n"; - ConvertSourceLocationToLineDirective(FinallyLoc, buf); - buf += "catch (id e) {_rethrow = e;}\n"; - } - - SourceLocation startFinalLoc = finalStmt->getLocStart(); - ReplaceText(startFinalLoc, 8, buf); - Stmt *body = finalStmt->getFinallyBody(); - SourceLocation startFinalBodyLoc = body->getLocStart(); - buf.clear(); - Write_RethrowObject(buf); - ReplaceText(startFinalBodyLoc, 1, buf); - - SourceLocation endFinalBodyLoc = body->getLocEnd(); - ReplaceText(endFinalBodyLoc, 1, "}\n}"); - // Now check for any return/continue/go statements within the @try. - WarnAboutReturnGotoStmts(S->getTryBody()); - } - - return nullptr; -} - -// This can't be done with ReplaceStmt(S, ThrowExpr), since -// the throw expression is typically a message expression that's already -// been rewritten! (which implies the SourceLocation's are invalid). -Stmt *RewriteModernObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) { - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @throw location"); - - std::string buf; - /* void objc_exception_throw(id) __attribute__((noreturn)); */ - if (S->getThrowExpr()) - buf = "objc_exception_throw("; - else - buf = "throw"; - - // handle "@ throw" correctly. - const char *wBuf = strchr(startBuf, 'w'); - assert((*wBuf == 'w') && "@throw: can't find 'w'"); - ReplaceText(startLoc, wBuf-startBuf+1, buf); - - SourceLocation endLoc = S->getLocEnd(); - const char *endBuf = SM->getCharacterData(endLoc); - const char *semiBuf = strchr(endBuf, ';'); - assert((*semiBuf == ';') && "@throw: can't find ';'"); - SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf); - if (S->getThrowExpr()) - ReplaceText(semiLoc, 1, ");"); - return nullptr; -} - -Stmt *RewriteModernObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) { - // Create a new string expression. - std::string StrEncoding; - Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding); - Expr *Replacement = getStringLiteral(StrEncoding); - ReplaceStmt(Exp, Replacement); - - // Replace this subexpr in the parent. - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return Replacement; -} - -Stmt *RewriteModernObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) { - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl"); - // Create a call to sel_registerName("selName"). - SmallVector<Expr*, 8> SelExprs; - SelExprs.push_back(getStringLiteral(Exp->getSelector().getAsString())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size()); - ReplaceStmt(Exp, SelExp); - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return SelExp; -} - -CallExpr *RewriteModernObjC::SynthesizeCallToFunctionDecl( - FunctionDecl *FD, Expr **args, unsigned nargs, SourceLocation StartLoc, - SourceLocation EndLoc) { - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = FD->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = - new (Context) DeclRefExpr(FD, false, msgSendType, VK_LValue, SourceLocation()); - - // Now, we cast the reference to a pointer to the objc_msgSend type. - QualType pToFunc = Context->getPointerType(msgSendType); - ImplicitCastExpr *ICE = - ImplicitCastExpr::Create(*Context, pToFunc, CK_FunctionToPointerDecay, - DRE, nullptr, VK_RValue); - - const FunctionType *FT = msgSendType->getAs<FunctionType>(); - - CallExpr *Exp = - new (Context) CallExpr(*Context, ICE, llvm::makeArrayRef(args, nargs), - FT->getCallResultType(*Context), - VK_RValue, EndLoc); - return Exp; -} - -static bool scanForProtocolRefs(const char *startBuf, const char *endBuf, - const char *&startRef, const char *&endRef) { - while (startBuf < endBuf) { - if (*startBuf == '<') - startRef = startBuf; // mark the start. - if (*startBuf == '>') { - if (startRef && *startRef == '<') { - endRef = startBuf; // mark the end. - return true; - } - return false; - } - startBuf++; - } - return false; -} - -static void scanToNextArgument(const char *&argRef) { - int angle = 0; - while (*argRef != ')' && (*argRef != ',' || angle > 0)) { - if (*argRef == '<') - angle++; - else if (*argRef == '>') - angle--; - argRef++; - } - assert(angle == 0 && "scanToNextArgument - bad protocol type syntax"); -} - -bool RewriteModernObjC::needToScanForQualifiers(QualType T) { - if (T->isObjCQualifiedIdType()) - return true; - if (const PointerType *PT = T->getAs<PointerType>()) { - if (PT->getPointeeType()->isObjCQualifiedIdType()) - return true; - } - if (T->isObjCObjectPointerType()) { - T = T->getPointeeType(); - return T->isObjCQualifiedInterfaceType(); - } - if (T->isArrayType()) { - QualType ElemTy = Context->getBaseElementType(T); - return needToScanForQualifiers(ElemTy); - } - return false; -} - -void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) { - QualType Type = E->getType(); - if (needToScanForQualifiers(Type)) { - SourceLocation Loc, EndLoc; - - if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) { - Loc = ECE->getLParenLoc(); - EndLoc = ECE->getRParenLoc(); - } else { - Loc = E->getLocStart(); - EndLoc = E->getLocEnd(); - } - // This will defend against trying to rewrite synthesized expressions. - if (Loc.isInvalid() || EndLoc.isInvalid()) - return; - - const char *startBuf = SM->getCharacterData(Loc); - const char *endBuf = SM->getCharacterData(EndLoc); - const char *startRef = nullptr, *endRef = nullptr; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = Loc.getLocWithOffset(startRef-startBuf); - SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-startBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*"); - InsertText(GreaterLoc, "*/"); - } - } -} - -void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { - SourceLocation Loc; - QualType Type; - const FunctionProtoType *proto = nullptr; - if (VarDecl *VD = dyn_cast<VarDecl>(Dcl)) { - Loc = VD->getLocation(); - Type = VD->getType(); - } - else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Dcl)) { - Loc = FD->getLocation(); - // Check for ObjC 'id' and class types that have been adorned with protocol - // information (id<p>, C<p>*). The protocol references need to be rewritten! - const FunctionType *funcType = FD->getType()->getAs<FunctionType>(); - assert(funcType && "missing function type"); - proto = dyn_cast<FunctionProtoType>(funcType); - if (!proto) - return; - Type = proto->getReturnType(); - } - else if (FieldDecl *FD = dyn_cast<FieldDecl>(Dcl)) { - Loc = FD->getLocation(); - Type = FD->getType(); - } - else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(Dcl)) { - Loc = TD->getLocation(); - Type = TD->getUnderlyingType(); - } - else - return; - - if (needToScanForQualifiers(Type)) { - // Since types are unique, we need to scan the buffer. - - const char *endBuf = SM->getCharacterData(Loc); - const char *startBuf = endBuf; - while (*startBuf != ';' && *startBuf != '<' && startBuf != MainFileStart) - startBuf--; // scan backward (from the decl location) for return type. - const char *startRef = nullptr, *endRef = nullptr; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = Loc.getLocWithOffset(startRef-endBuf); - SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-endBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*"); - InsertText(GreaterLoc, "*/"); - } - } - if (!proto) - return; // most likely, was a variable - // Now check arguments. - const char *startBuf = SM->getCharacterData(Loc); - const char *startFuncBuf = startBuf; - for (unsigned i = 0; i < proto->getNumParams(); i++) { - if (needToScanForQualifiers(proto->getParamType(i))) { - // Since types are unique, we need to scan the buffer. - - const char *endBuf = startBuf; - // scan forward (from the decl location) for argument types. - scanToNextArgument(endBuf); - const char *startRef = nullptr, *endRef = nullptr; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = - Loc.getLocWithOffset(startRef-startFuncBuf); - SourceLocation GreaterLoc = - Loc.getLocWithOffset(endRef-startFuncBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*"); - InsertText(GreaterLoc, "*/"); - } - startBuf = ++endBuf; - } - else { - // If the function name is derived from a macro expansion, then the - // argument buffer will not follow the name. Need to speak with Chris. - while (*startBuf && *startBuf != ')' && *startBuf != ',') - startBuf++; // scan forward (from the decl location) for argument types. - startBuf++; - } - } -} - -void RewriteModernObjC::RewriteTypeOfDecl(VarDecl *ND) { - QualType QT = ND->getType(); - const Type* TypePtr = QT->getAs<Type>(); - if (!isa<TypeOfExprType>(TypePtr)) - return; - while (isa<TypeOfExprType>(TypePtr)) { - const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr); - QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); - TypePtr = QT->getAs<Type>(); - } - // FIXME. This will not work for multiple declarators; as in: - // __typeof__(a) b,c,d; - std::string TypeAsString(QT.getAsString(Context->getPrintingPolicy())); - SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); - const char *startBuf = SM->getCharacterData(DeclLoc); - if (ND->getInit()) { - std::string Name(ND->getNameAsString()); - TypeAsString += " " + Name + " = "; - Expr *E = ND->getInit(); - SourceLocation startLoc; - if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) - startLoc = ECE->getLParenLoc(); - else - startLoc = E->getLocStart(); - startLoc = SM->getExpansionLoc(startLoc); - const char *endBuf = SM->getCharacterData(startLoc); - ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); - } - else { - SourceLocation X = ND->getLocEnd(); - X = SM->getExpansionLoc(X); - const char *endBuf = SM->getCharacterData(X); - ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); - } -} - -// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str); -void RewriteModernObjC::SynthSelGetUidFunctionDecl() { - IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName"); - SmallVector<QualType, 16> ArgTys; - ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); - QualType getFuncType = - getSimpleFunctionType(Context->getObjCSelType(), ArgTys); - SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - SelGetUidIdent, getFuncType, - nullptr, SC_Extern); -} - -void RewriteModernObjC::RewriteFunctionDecl(FunctionDecl *FD) { - // declared in <objc/objc.h> - if (FD->getIdentifier() && - FD->getName() == "sel_registerName") { - SelGetUidFunctionDecl = FD; - return; - } - RewriteObjCQualifiedInterfaceTypes(FD); -} - -void RewriteModernObjC::RewriteBlockPointerType(std::string& Str, QualType Type) { - std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); - const char *argPtr = TypeString.c_str(); - if (!strchr(argPtr, '^')) { - Str += TypeString; - return; - } - while (*argPtr) { - Str += (*argPtr == '^' ? '*' : *argPtr); - argPtr++; - } -} - -// FIXME. Consolidate this routine with RewriteBlockPointerType. -void RewriteModernObjC::RewriteBlockPointerTypeVariable(std::string& Str, - ValueDecl *VD) { - QualType Type = VD->getType(); - std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); - const char *argPtr = TypeString.c_str(); - int paren = 0; - while (*argPtr) { - switch (*argPtr) { - case '(': - Str += *argPtr; - paren++; - break; - case ')': - Str += *argPtr; - paren--; - break; - case '^': - Str += '*'; - if (paren == 1) - Str += VD->getNameAsString(); - break; - default: - Str += *argPtr; - break; - } - argPtr++; - } -} - -void RewriteModernObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) { - SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); - const FunctionType *funcType = FD->getType()->getAs<FunctionType>(); - const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(funcType); - if (!proto) - return; - QualType Type = proto->getReturnType(); - std::string FdStr = Type.getAsString(Context->getPrintingPolicy()); - FdStr += " "; - FdStr += FD->getName(); - FdStr += "("; - unsigned numArgs = proto->getNumParams(); - for (unsigned i = 0; i < numArgs; i++) { - QualType ArgType = proto->getParamType(i); - RewriteBlockPointerType(FdStr, ArgType); - if (i+1 < numArgs) - FdStr += ", "; - } - if (FD->isVariadic()) { - FdStr += (numArgs > 0) ? ", ...);\n" : "...);\n"; - } - else - FdStr += ");\n"; - InsertText(FunLocStart, FdStr); -} - -// SynthSuperConstructorFunctionDecl - id __rw_objc_super(id obj, id super); -void RewriteModernObjC::SynthSuperConstructorFunctionDecl() { - if (SuperConstructorFunctionDecl) - return; - IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super"); - SmallVector<QualType, 16> ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - ArgTys); - SuperConstructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, - nullptr, SC_Extern); -} - -// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...); -void RewriteModernObjC::SynthMsgSendFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend"); - SmallVector<QualType, 16> ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - ArgTys, /*isVariadic=*/true); - MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, nullptr, - SC_Extern); -} - -// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(void); -void RewriteModernObjC::SynthMsgSendSuperFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper"); - SmallVector<QualType, 2> ArgTys; - ArgTys.push_back(Context->VoidTy); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - ArgTys, /*isVariadic=*/true); - MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, - nullptr, SC_Extern); -} - -// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...); -void RewriteModernObjC::SynthMsgSendStretFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret"); - SmallVector<QualType, 16> ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - ArgTys, /*isVariadic=*/true); - MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, - nullptr, SC_Extern); -} - -// SynthMsgSendSuperStretFunctionDecl - -// id objc_msgSendSuper_stret(void); -void RewriteModernObjC::SynthMsgSendSuperStretFunctionDecl() { - IdentifierInfo *msgSendIdent = - &Context->Idents.get("objc_msgSendSuper_stret"); - SmallVector<QualType, 2> ArgTys; - ArgTys.push_back(Context->VoidTy); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - ArgTys, /*isVariadic=*/true); - MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, - msgSendType, nullptr, - SC_Extern); -} - -// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...); -void RewriteModernObjC::SynthMsgSendFpretFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret"); - SmallVector<QualType, 16> ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->DoubleTy, - ArgTys, /*isVariadic=*/true); - MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, - nullptr, SC_Extern); -} - -// SynthGetClassFunctionDecl - Class objc_getClass(const char *name); -void RewriteModernObjC::SynthGetClassFunctionDecl() { - IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass"); - SmallVector<QualType, 16> ArgTys; - ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); - QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(), - ArgTys); - GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - getClassIdent, getClassType, - nullptr, SC_Extern); -} - -// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls); -void RewriteModernObjC::SynthGetSuperClassFunctionDecl() { - IdentifierInfo *getSuperClassIdent = - &Context->Idents.get("class_getSuperclass"); - SmallVector<QualType, 16> ArgTys; - ArgTys.push_back(Context->getObjCClassType()); - QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(), - ArgTys); - GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - getSuperClassIdent, - getClassType, nullptr, - SC_Extern); -} - -// SynthGetMetaClassFunctionDecl - Class objc_getMetaClass(const char *name); -void RewriteModernObjC::SynthGetMetaClassFunctionDecl() { - IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass"); - SmallVector<QualType, 16> ArgTys; - ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); - QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(), - ArgTys); - GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - getClassIdent, getClassType, - nullptr, SC_Extern); -} - -Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { - assert (Exp != nullptr && "Expected non-null ObjCStringLiteral"); - QualType strType = getConstantStringStructType(); - - std::string S = "__NSConstantStringImpl_"; - - std::string tmpName = InFileName; - unsigned i; - for (i=0; i < tmpName.length(); i++) { - char c = tmpName.at(i); - // replace any non-alphanumeric characters with '_'. - if (!isAlphanumeric(c)) - tmpName[i] = '_'; - } - S += tmpName; - S += "_"; - S += utostr(NumObjCStringLiterals++); - - Preamble += "static __NSConstantStringImpl " + S; - Preamble += " __attribute__ ((section (\"__DATA, __cfstring\"))) = {__CFConstantStringClassReference,"; - Preamble += "0x000007c8,"; // utf8_str - // The pretty printer for StringLiteral handles escape characters properly. - std::string prettyBufS; - llvm::raw_string_ostream prettyBuf(prettyBufS); - Exp->getString()->printPretty(prettyBuf, nullptr, PrintingPolicy(LangOpts)); - Preamble += prettyBuf.str(); - Preamble += ","; - Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; - - VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), &Context->Idents.get(S), - strType, nullptr, SC_Static); - DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue, - SourceLocation()); - Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, - Context->getPointerType(DRE->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - // cast to NSConstantString * - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), - CK_CPointerToObjCPointerCast, Unop); - ReplaceStmt(Exp, cast); - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return cast; -} - -Stmt *RewriteModernObjC::RewriteObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Exp) { - unsigned IntSize = - static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); - - Expr *FlagExp = IntegerLiteral::Create(*Context, - llvm::APInt(IntSize, Exp->getValue()), - Context->IntTy, Exp->getLocation()); - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Context->ObjCBuiltinBoolTy, - CK_BitCast, FlagExp); - ParenExpr *PE = new (Context) ParenExpr(Exp->getLocation(), Exp->getExprLoc(), - cast); - ReplaceStmt(Exp, PE); - return PE; -} - -Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) { - // synthesize declaration of helper functions needed in this routine. - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - // use objc_msgSend() for all. - if (!MsgSendFunctionDecl) - SynthMsgSendFunctionDecl(); - if (!GetClassFunctionDecl) - SynthGetClassFunctionDecl(); - - FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; - SourceLocation StartLoc = Exp->getLocStart(); - SourceLocation EndLoc = Exp->getLocEnd(); - - // Synthesize a call to objc_msgSend(). - SmallVector<Expr*, 4> MsgExprs; - SmallVector<Expr*, 4> ClsExprs; - - // Create a call to objc_getClass("<BoxingClass>"). It will be the 1st argument. - ObjCMethodDecl *BoxingMethod = Exp->getBoxingMethod(); - ObjCInterfaceDecl *BoxingClass = BoxingMethod->getClassInterface(); - - IdentifierInfo *clsName = BoxingClass->getIdentifier(); - ClsExprs.push_back(getStringLiteral(clsName->getName())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(Cls); - - // Create a call to sel_registerName("<BoxingMethod>:"), etc. - // it will be the 2nd argument. - SmallVector<Expr*, 4> SelExprs; - SelExprs.push_back( - getStringLiteral(BoxingMethod->getSelector().getAsString())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(SelExp); - - // User provided sub-expression is the 3rd, and last, argument. - Expr *subExpr = Exp->getSubExpr(); - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(subExpr)) { - QualType type = ICE->getType(); - const Expr *SubExpr = ICE->IgnoreParenImpCasts(); - CastKind CK = CK_BitCast; - if (SubExpr->getType()->isIntegralType(*Context) && type->isBooleanType()) - CK = CK_IntegralToBoolean; - subExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, subExpr); - } - MsgExprs.push_back(subExpr); - - SmallVector<QualType, 4> ArgTypes; - ArgTypes.push_back(Context->getObjCIdType()); - ArgTypes.push_back(Context->getObjCSelType()); - for (const auto PI : BoxingMethod->parameters()) - ArgTypes.push_back(PI->getType()); - - QualType returnType = Exp->getType(); - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = MsgSendFlavor->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, - VK_LValue, SourceLocation()); - - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->VoidTy), - CK_BitCast, DRE); - - // Now do the "normal" pointer to function cast. - QualType castType = - getSimpleFunctionType(returnType, ArgTypes, BoxingMethod->isVariadic()); - castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, - cast); - - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); - - const FunctionType *FT = msgSendType->getAs<FunctionType>(); - CallExpr *CE = new (Context) - CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc); - ReplaceStmt(Exp, CE); - return CE; -} - -Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) { - // synthesize declaration of helper functions needed in this routine. - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - // use objc_msgSend() for all. - if (!MsgSendFunctionDecl) - SynthMsgSendFunctionDecl(); - if (!GetClassFunctionDecl) - SynthGetClassFunctionDecl(); - - FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; - SourceLocation StartLoc = Exp->getLocStart(); - SourceLocation EndLoc = Exp->getLocEnd(); - - // Build the expression: __NSContainer_literal(int, ...).arr - QualType IntQT = Context->IntTy; - QualType NSArrayFType = - getSimpleFunctionType(Context->VoidTy, IntQT, true); - std::string NSArrayFName("__NSContainer_literal"); - FunctionDecl *NSArrayFD = SynthBlockInitFunctionDecl(NSArrayFName); - DeclRefExpr *NSArrayDRE = - new (Context) DeclRefExpr(NSArrayFD, false, NSArrayFType, VK_RValue, - SourceLocation()); - - SmallVector<Expr*, 16> InitExprs; - unsigned NumElements = Exp->getNumElements(); - unsigned UnsignedIntSize = - static_cast<unsigned>(Context->getTypeSize(Context->UnsignedIntTy)); - Expr *count = IntegerLiteral::Create(*Context, - llvm::APInt(UnsignedIntSize, NumElements), - Context->UnsignedIntTy, SourceLocation()); - InitExprs.push_back(count); - for (unsigned i = 0; i < NumElements; i++) - InitExprs.push_back(Exp->getElement(i)); - Expr *NSArrayCallExpr = - new (Context) CallExpr(*Context, NSArrayDRE, InitExprs, - NSArrayFType, VK_LValue, SourceLocation()); - - FieldDecl *ARRFD = FieldDecl::Create(*Context, nullptr, SourceLocation(), - SourceLocation(), - &Context->Idents.get("arr"), - Context->getPointerType(Context->VoidPtrTy), - nullptr, /*BitWidth=*/nullptr, - /*Mutable=*/true, ICIS_NoInit); - MemberExpr *ArrayLiteralME = - new (Context) MemberExpr(NSArrayCallExpr, false, ARRFD, - SourceLocation(), - ARRFD->getType(), VK_LValue, - OK_Ordinary); - QualType ConstIdT = Context->getObjCIdType().withConst(); - CStyleCastExpr * ArrayLiteralObjects = - NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(ConstIdT), - CK_BitCast, - ArrayLiteralME); - - // Synthesize a call to objc_msgSend(). - SmallVector<Expr*, 32> MsgExprs; - SmallVector<Expr*, 4> ClsExprs; - QualType expType = Exp->getType(); - - // Create a call to objc_getClass("NSArray"). It will be th 1st argument. - ObjCInterfaceDecl *Class = - expType->getPointeeType()->getAs<ObjCObjectType>()->getInterface(); - - IdentifierInfo *clsName = Class->getIdentifier(); - ClsExprs.push_back(getStringLiteral(clsName->getName())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(Cls); - - // Create a call to sel_registerName("arrayWithObjects:count:"). - // it will be the 2nd argument. - SmallVector<Expr*, 4> SelExprs; - ObjCMethodDecl *ArrayMethod = Exp->getArrayWithObjectsMethod(); - SelExprs.push_back( - getStringLiteral(ArrayMethod->getSelector().getAsString())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(SelExp); - - // (const id [])objects - MsgExprs.push_back(ArrayLiteralObjects); - - // (NSUInteger)cnt - Expr *cnt = IntegerLiteral::Create(*Context, - llvm::APInt(UnsignedIntSize, NumElements), - Context->UnsignedIntTy, SourceLocation()); - MsgExprs.push_back(cnt); - - - SmallVector<QualType, 4> ArgTypes; - ArgTypes.push_back(Context->getObjCIdType()); - ArgTypes.push_back(Context->getObjCSelType()); - for (const auto *PI : ArrayMethod->params()) - ArgTypes.push_back(PI->getType()); - - QualType returnType = Exp->getType(); - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = MsgSendFlavor->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, - VK_LValue, SourceLocation()); - - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->VoidTy), - CK_BitCast, DRE); - - // Now do the "normal" pointer to function cast. - QualType castType = - getSimpleFunctionType(returnType, ArgTypes, ArrayMethod->isVariadic()); - castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, - cast); - - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); - - const FunctionType *FT = msgSendType->getAs<FunctionType>(); - CallExpr *CE = new (Context) - CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc); - ReplaceStmt(Exp, CE); - return CE; -} - -Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral *Exp) { - // synthesize declaration of helper functions needed in this routine. - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - // use objc_msgSend() for all. - if (!MsgSendFunctionDecl) - SynthMsgSendFunctionDecl(); - if (!GetClassFunctionDecl) - SynthGetClassFunctionDecl(); - - FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; - SourceLocation StartLoc = Exp->getLocStart(); - SourceLocation EndLoc = Exp->getLocEnd(); - - // Build the expression: __NSContainer_literal(int, ...).arr - QualType IntQT = Context->IntTy; - QualType NSDictFType = - getSimpleFunctionType(Context->VoidTy, IntQT, true); - std::string NSDictFName("__NSContainer_literal"); - FunctionDecl *NSDictFD = SynthBlockInitFunctionDecl(NSDictFName); - DeclRefExpr *NSDictDRE = - new (Context) DeclRefExpr(NSDictFD, false, NSDictFType, VK_RValue, - SourceLocation()); - - SmallVector<Expr*, 16> KeyExprs; - SmallVector<Expr*, 16> ValueExprs; - - unsigned NumElements = Exp->getNumElements(); - unsigned UnsignedIntSize = - static_cast<unsigned>(Context->getTypeSize(Context->UnsignedIntTy)); - Expr *count = IntegerLiteral::Create(*Context, - llvm::APInt(UnsignedIntSize, NumElements), - Context->UnsignedIntTy, SourceLocation()); - KeyExprs.push_back(count); - ValueExprs.push_back(count); - for (unsigned i = 0; i < NumElements; i++) { - ObjCDictionaryElement Element = Exp->getKeyValueElement(i); - KeyExprs.push_back(Element.Key); - ValueExprs.push_back(Element.Value); - } - - // (const id [])objects - Expr *NSValueCallExpr = - new (Context) CallExpr(*Context, NSDictDRE, ValueExprs, - NSDictFType, VK_LValue, SourceLocation()); - - FieldDecl *ARRFD = FieldDecl::Create(*Context, nullptr, SourceLocation(), - SourceLocation(), - &Context->Idents.get("arr"), - Context->getPointerType(Context->VoidPtrTy), - nullptr, /*BitWidth=*/nullptr, - /*Mutable=*/true, ICIS_NoInit); - MemberExpr *DictLiteralValueME = - new (Context) MemberExpr(NSValueCallExpr, false, ARRFD, - SourceLocation(), - ARRFD->getType(), VK_LValue, - OK_Ordinary); - QualType ConstIdT = Context->getObjCIdType().withConst(); - CStyleCastExpr * DictValueObjects = - NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(ConstIdT), - CK_BitCast, - DictLiteralValueME); - // (const id <NSCopying> [])keys - Expr *NSKeyCallExpr = - new (Context) CallExpr(*Context, NSDictDRE, KeyExprs, - NSDictFType, VK_LValue, SourceLocation()); - - MemberExpr *DictLiteralKeyME = - new (Context) MemberExpr(NSKeyCallExpr, false, ARRFD, - SourceLocation(), - ARRFD->getType(), VK_LValue, - OK_Ordinary); - - CStyleCastExpr * DictKeyObjects = - NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(ConstIdT), - CK_BitCast, - DictLiteralKeyME); - - - - // Synthesize a call to objc_msgSend(). - SmallVector<Expr*, 32> MsgExprs; - SmallVector<Expr*, 4> ClsExprs; - QualType expType = Exp->getType(); - - // Create a call to objc_getClass("NSArray"). It will be th 1st argument. - ObjCInterfaceDecl *Class = - expType->getPointeeType()->getAs<ObjCObjectType>()->getInterface(); - - IdentifierInfo *clsName = Class->getIdentifier(); - ClsExprs.push_back(getStringLiteral(clsName->getName())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(Cls); - - // Create a call to sel_registerName("arrayWithObjects:count:"). - // it will be the 2nd argument. - SmallVector<Expr*, 4> SelExprs; - ObjCMethodDecl *DictMethod = Exp->getDictWithObjectsMethod(); - SelExprs.push_back(getStringLiteral(DictMethod->getSelector().getAsString())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(SelExp); - - // (const id [])objects - MsgExprs.push_back(DictValueObjects); - - // (const id <NSCopying> [])keys - MsgExprs.push_back(DictKeyObjects); - - // (NSUInteger)cnt - Expr *cnt = IntegerLiteral::Create(*Context, - llvm::APInt(UnsignedIntSize, NumElements), - Context->UnsignedIntTy, SourceLocation()); - MsgExprs.push_back(cnt); - - - SmallVector<QualType, 8> ArgTypes; - ArgTypes.push_back(Context->getObjCIdType()); - ArgTypes.push_back(Context->getObjCSelType()); - for (const auto *PI : DictMethod->params()) { - QualType T = PI->getType(); - if (const PointerType* PT = T->getAs<PointerType>()) { - QualType PointeeTy = PT->getPointeeType(); - convertToUnqualifiedObjCType(PointeeTy); - T = Context->getPointerType(PointeeTy); - } - ArgTypes.push_back(T); - } - - QualType returnType = Exp->getType(); - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = MsgSendFlavor->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, - VK_LValue, SourceLocation()); - - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->VoidTy), - CK_BitCast, DRE); - - // Now do the "normal" pointer to function cast. - QualType castType = - getSimpleFunctionType(returnType, ArgTypes, DictMethod->isVariadic()); - castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, - cast); - - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); - - const FunctionType *FT = msgSendType->getAs<FunctionType>(); - CallExpr *CE = new (Context) - CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc); - ReplaceStmt(Exp, CE); - return CE; -} - -// struct __rw_objc_super { -// struct objc_object *object; struct objc_object *superClass; -// }; -QualType RewriteModernObjC::getSuperStructType() { - if (!SuperStructDecl) { - SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("__rw_objc_super")); - QualType FieldTypes[2]; - - // struct objc_object *object; - FieldTypes[0] = Context->getObjCIdType(); - // struct objc_object *superClass; - FieldTypes[1] = Context->getObjCIdType(); - - // Create fields - for (unsigned i = 0; i < 2; ++i) { - SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl, - SourceLocation(), - SourceLocation(), nullptr, - FieldTypes[i], nullptr, - /*BitWidth=*/nullptr, - /*Mutable=*/false, - ICIS_NoInit)); - } - - SuperStructDecl->completeDefinition(); - } - return Context->getTagDeclType(SuperStructDecl); -} - -QualType RewriteModernObjC::getConstantStringStructType() { - if (!ConstantStringDecl) { - ConstantStringDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("__NSConstantStringImpl")); - QualType FieldTypes[4]; - - // struct objc_object *receiver; - FieldTypes[0] = Context->getObjCIdType(); - // int flags; - FieldTypes[1] = Context->IntTy; - // char *str; - FieldTypes[2] = Context->getPointerType(Context->CharTy); - // long length; - FieldTypes[3] = Context->LongTy; - - // Create fields - for (unsigned i = 0; i < 4; ++i) { - ConstantStringDecl->addDecl(FieldDecl::Create(*Context, - ConstantStringDecl, - SourceLocation(), - SourceLocation(), nullptr, - FieldTypes[i], nullptr, - /*BitWidth=*/nullptr, - /*Mutable=*/true, - ICIS_NoInit)); - } - - ConstantStringDecl->completeDefinition(); - } - return Context->getTagDeclType(ConstantStringDecl); -} - -/// getFunctionSourceLocation - returns start location of a function -/// definition. Complication arises when function has declared as -/// extern "C" or extern "C" {...} -static SourceLocation getFunctionSourceLocation (RewriteModernObjC &R, - FunctionDecl *FD) { - if (FD->isExternC() && !FD->isMain()) { - const DeclContext *DC = FD->getDeclContext(); - if (const LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(DC)) - // if it is extern "C" {...}, return function decl's own location. - if (!LSD->getRBraceLoc().isValid()) - return LSD->getExternLoc(); - } - if (FD->getStorageClass() != SC_None) - R.RewriteBlockLiteralFunctionDecl(FD); - return FD->getTypeSpecStartLoc(); -} - -void RewriteModernObjC::RewriteLineDirective(const Decl *D) { - - SourceLocation Location = D->getLocation(); - - if (Location.isFileID() && GenerateLineInfo) { - std::string LineString("\n#line "); - PresumedLoc PLoc = SM->getPresumedLoc(Location); - LineString += utostr(PLoc.getLine()); - LineString += " \""; - LineString += Lexer::Stringify(PLoc.getFilename()); - if (isa<ObjCMethodDecl>(D)) - LineString += "\""; - else LineString += "\"\n"; - - Location = D->getLocStart(); - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - if (FD->isExternC() && !FD->isMain()) { - const DeclContext *DC = FD->getDeclContext(); - if (const LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(DC)) - // if it is extern "C" {...}, return function decl's own location. - if (!LSD->getRBraceLoc().isValid()) - Location = LSD->getExternLoc(); - } - } - InsertText(Location, LineString); - } -} - -/// SynthMsgSendStretCallExpr - This routine translates message expression -/// into a call to objc_msgSend_stret() entry point. Tricky part is that -/// nil check on receiver must be performed before calling objc_msgSend_stret. -/// MsgSendStretFlavor - function declaration objc_msgSend_stret(...) -/// msgSendType - function type of objc_msgSend_stret(...) -/// returnType - Result type of the method being synthesized. -/// ArgTypes - type of the arguments passed to objc_msgSend_stret, starting with receiver type. -/// MsgExprs - list of argument expressions being passed to objc_msgSend_stret, -/// starting with receiver. -/// Method - Method being rewritten. -Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, - QualType returnType, - SmallVectorImpl<QualType> &ArgTypes, - SmallVectorImpl<Expr*> &MsgExprs, - ObjCMethodDecl *Method) { - // Now do the "normal" pointer to function cast. - QualType castType = getSimpleFunctionType(returnType, ArgTypes, - Method ? Method->isVariadic() - : false); - castType = Context->getPointerType(castType); - - // build type for containing the objc_msgSend_stret object. - static unsigned stretCount=0; - std::string name = "__Stret"; name += utostr(stretCount); - std::string str = - "extern \"C\" void * __cdecl memset(void *_Dst, int _Val, size_t _Size);\n"; - str += "namespace {\n"; - str += "struct "; str += name; - str += " {\n\t"; - str += name; - str += "(id receiver, SEL sel"; - for (unsigned i = 2; i < ArgTypes.size(); i++) { - std::string ArgName = "arg"; ArgName += utostr(i); - ArgTypes[i].getAsStringInternal(ArgName, Context->getPrintingPolicy()); - str += ", "; str += ArgName; - } - // could be vararg. - for (unsigned i = ArgTypes.size(); i < MsgExprs.size(); i++) { - std::string ArgName = "arg"; ArgName += utostr(i); - MsgExprs[i]->getType().getAsStringInternal(ArgName, - Context->getPrintingPolicy()); - str += ", "; str += ArgName; - } - - str += ") {\n"; - str += "\t unsigned size = sizeof("; - str += returnType.getAsString(Context->getPrintingPolicy()); str += ");\n"; - - str += "\t if (size == 1 || size == 2 || size == 4 || size == 8)\n"; - - str += "\t s = (("; str += castType.getAsString(Context->getPrintingPolicy()); - str += ")(void *)objc_msgSend)(receiver, sel"; - for (unsigned i = 2; i < ArgTypes.size(); i++) { - str += ", arg"; str += utostr(i); - } - // could be vararg. - for (unsigned i = ArgTypes.size(); i < MsgExprs.size(); i++) { - str += ", arg"; str += utostr(i); - } - str+= ");\n"; - - str += "\t else if (receiver == 0)\n"; - str += "\t memset((void*)&s, 0, sizeof(s));\n"; - str += "\t else\n"; - - - str += "\t s = (("; str += castType.getAsString(Context->getPrintingPolicy()); - str += ")(void *)objc_msgSend_stret)(receiver, sel"; - for (unsigned i = 2; i < ArgTypes.size(); i++) { - str += ", arg"; str += utostr(i); - } - // could be vararg. - for (unsigned i = ArgTypes.size(); i < MsgExprs.size(); i++) { - str += ", arg"; str += utostr(i); - } - str += ");\n"; - - - str += "\t}\n"; - str += "\t"; str += returnType.getAsString(Context->getPrintingPolicy()); - str += " s;\n"; - str += "};\n};\n\n"; - SourceLocation FunLocStart; - if (CurFunctionDef) - FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef); - else { - assert(CurMethodDef && "SynthMsgSendStretCallExpr - CurMethodDef is null"); - FunLocStart = CurMethodDef->getLocStart(); - } - - InsertText(FunLocStart, str); - ++stretCount; - - // AST for __Stretn(receiver, args).s; - IdentifierInfo *ID = &Context->Idents.get(name); - FunctionDecl *FD = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), ID, castType, - nullptr, SC_Extern, false, false); - DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, castType, VK_RValue, - SourceLocation()); - CallExpr *STCE = new (Context) CallExpr(*Context, DRE, MsgExprs, - castType, VK_LValue, SourceLocation()); - - FieldDecl *FieldD = FieldDecl::Create(*Context, nullptr, SourceLocation(), - SourceLocation(), - &Context->Idents.get("s"), - returnType, nullptr, - /*BitWidth=*/nullptr, - /*Mutable=*/true, ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(STCE, false, FieldD, SourceLocation(), - FieldD->getType(), VK_LValue, - OK_Ordinary); - - return ME; -} - -Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, - SourceLocation StartLoc, - SourceLocation EndLoc) { - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - if (!MsgSendFunctionDecl) - SynthMsgSendFunctionDecl(); - if (!MsgSendSuperFunctionDecl) - SynthMsgSendSuperFunctionDecl(); - if (!MsgSendStretFunctionDecl) - SynthMsgSendStretFunctionDecl(); - if (!MsgSendSuperStretFunctionDecl) - SynthMsgSendSuperStretFunctionDecl(); - if (!MsgSendFpretFunctionDecl) - SynthMsgSendFpretFunctionDecl(); - if (!GetClassFunctionDecl) - SynthGetClassFunctionDecl(); - if (!GetSuperClassFunctionDecl) - SynthGetSuperClassFunctionDecl(); - if (!GetMetaClassFunctionDecl) - SynthGetMetaClassFunctionDecl(); - - // default to objc_msgSend(). - FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; - // May need to use objc_msgSend_stret() as well. - FunctionDecl *MsgSendStretFlavor = nullptr; - if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) { - QualType resultType = mDecl->getReturnType(); - if (resultType->isRecordType()) - MsgSendStretFlavor = MsgSendStretFunctionDecl; - else if (resultType->isRealFloatingType()) - MsgSendFlavor = MsgSendFpretFunctionDecl; - } - - // Synthesize a call to objc_msgSend(). - SmallVector<Expr*, 8> MsgExprs; - switch (Exp->getReceiverKind()) { - case ObjCMessageExpr::SuperClass: { - MsgSendFlavor = MsgSendSuperFunctionDecl; - if (MsgSendStretFlavor) - MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; - assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - - ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); - - SmallVector<Expr*, 4> InitExprs; - - // set the receiver to self, the first argument to all methods. - InitExprs.push_back( - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, - new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), - false, - Context->getObjCIdType(), - VK_RValue, - SourceLocation())) - ); // set the 'receiver'. - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - SmallVector<Expr*, 8> ClsExprs; - ClsExprs.push_back(getStringLiteral(ClassDecl->getIdentifier()->getName())); - // (Class)objc_getClass("CurrentClass") - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, - EndLoc); - ClsExprs.clear(); - ClsExprs.push_back(Cls); - Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, - &ClsExprs[0], ClsExprs.size(), - StartLoc, EndLoc); - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - // To turn off a warning, type-cast to 'id' - InitExprs.push_back( // set 'super class', using class_getSuperclass(). - NoTypeInfoCStyleCastExpr(Context, - Context->getObjCIdType(), - CK_BitCast, Cls)); - // struct __rw_objc_super - QualType superType = getSuperStructType(); - Expr *SuperRep; - - if (LangOpts.MicrosoftExt) { - SynthSuperConstructorFunctionDecl(); - // Simulate a constructor call... - DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperConstructorFunctionDecl, - false, superType, VK_LValue, - SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs, - superType, VK_LValue, - SourceLocation()); - // The code for super is a little tricky to prevent collision with - // the structure definition in the header. The rewriter has it's own - // internal definition (__rw_objc_super) that is uses. This is why - // we need the cast below. For example: - // (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) - // - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, - Context->getPointerType(SuperRep->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - SuperRep = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(superType), - CK_BitCast, SuperRep); - } else { - // (struct __rw_objc_super) { <exprs from above> } - InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, - SourceLocation()); - TypeSourceInfo *superTInfo - = Context->getTrivialTypeSourceInfo(superType); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, - superType, VK_LValue, - ILE, false); - // struct __rw_objc_super * - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, - Context->getPointerType(SuperRep->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - } - MsgExprs.push_back(SuperRep); - break; - } - - case ObjCMessageExpr::Class: { - SmallVector<Expr*, 8> ClsExprs; - ObjCInterfaceDecl *Class - = Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface(); - IdentifierInfo *clsName = Class->getIdentifier(); - ClsExprs.push_back(getStringLiteral(clsName->getName())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, - Context->getObjCIdType(), - CK_BitCast, Cls); - MsgExprs.push_back(ArgExpr); - break; - } - - case ObjCMessageExpr::SuperInstance:{ - MsgSendFlavor = MsgSendSuperFunctionDecl; - if (MsgSendStretFlavor) - MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; - assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); - SmallVector<Expr*, 4> InitExprs; - - InitExprs.push_back( - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, - new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), - false, - Context->getObjCIdType(), - VK_RValue, SourceLocation())) - ); // set the 'receiver'. - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - SmallVector<Expr*, 8> ClsExprs; - ClsExprs.push_back(getStringLiteral(ClassDecl->getIdentifier()->getName())); - // (Class)objc_getClass("CurrentClass") - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - ClsExprs.clear(); - ClsExprs.push_back(Cls); - Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, - &ClsExprs[0], ClsExprs.size(), - StartLoc, EndLoc); - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - // To turn off a warning, type-cast to 'id' - InitExprs.push_back( - // set 'super class', using class_getSuperclass(). - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, Cls)); - // struct __rw_objc_super - QualType superType = getSuperStructType(); - Expr *SuperRep; - - if (LangOpts.MicrosoftExt) { - SynthSuperConstructorFunctionDecl(); - // Simulate a constructor call... - DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperConstructorFunctionDecl, - false, superType, VK_LValue, - SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs, - superType, VK_LValue, SourceLocation()); - // The code for super is a little tricky to prevent collision with - // the structure definition in the header. The rewriter has it's own - // internal definition (__rw_objc_super) that is uses. This is why - // we need the cast below. For example: - // (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) - // - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, - Context->getPointerType(SuperRep->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - SuperRep = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(superType), - CK_BitCast, SuperRep); - } else { - // (struct __rw_objc_super) { <exprs from above> } - InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, - SourceLocation()); - TypeSourceInfo *superTInfo - = Context->getTrivialTypeSourceInfo(superType); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, - superType, VK_RValue, ILE, - false); - } - MsgExprs.push_back(SuperRep); - break; - } - - case ObjCMessageExpr::Instance: { - // Remove all type-casts because it may contain objc-style types; e.g. - // Foo<Proto> *. - Expr *recExpr = Exp->getInstanceReceiver(); - while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr)) - recExpr = CE->getSubExpr(); - CastKind CK = recExpr->getType()->isObjCObjectPointerType() - ? CK_BitCast : recExpr->getType()->isBlockPointerType() - ? CK_BlockPointerToObjCPointerCast - : CK_CPointerToObjCPointerCast; - - recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK, recExpr); - MsgExprs.push_back(recExpr); - break; - } - } - - // Create a call to sel_registerName("selName"), it will be the 2nd argument. - SmallVector<Expr*, 8> SelExprs; - SelExprs.push_back(getStringLiteral(Exp->getSelector().getAsString())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size(), - StartLoc, - EndLoc); - MsgExprs.push_back(SelExp); - - // Now push any user supplied arguments. - for (unsigned i = 0; i < Exp->getNumArgs(); i++) { - Expr *userExpr = Exp->getArg(i); - // Make all implicit casts explicit...ICE comes in handy:-) - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) { - // Reuse the ICE type, it is exactly what the doctor ordered. - QualType type = ICE->getType(); - if (needToScanForQualifiers(type)) - type = Context->getObjCIdType(); - // Make sure we convert "type (^)(...)" to "type (*)(...)". - (void)convertBlockPointerToFunctionPointer(type); - const Expr *SubExpr = ICE->IgnoreParenImpCasts(); - CastKind CK; - if (SubExpr->getType()->isIntegralType(*Context) && - type->isBooleanType()) { - CK = CK_IntegralToBoolean; - } else if (type->isObjCObjectPointerType()) { - if (SubExpr->getType()->isBlockPointerType()) { - CK = CK_BlockPointerToObjCPointerCast; - } else if (SubExpr->getType()->isPointerType()) { - CK = CK_CPointerToObjCPointerCast; - } else { - CK = CK_BitCast; - } - } else { - CK = CK_BitCast; - } - - userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, userExpr); - } - // Make id<P...> cast into an 'id' cast. - else if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(userExpr)) { - if (CE->getType()->isObjCQualifiedIdType()) { - while ((CE = dyn_cast<CStyleCastExpr>(userExpr))) - userExpr = CE->getSubExpr(); - CastKind CK; - if (userExpr->getType()->isIntegralType(*Context)) { - CK = CK_IntegralToPointer; - } else if (userExpr->getType()->isBlockPointerType()) { - CK = CK_BlockPointerToObjCPointerCast; - } else if (userExpr->getType()->isPointerType()) { - CK = CK_CPointerToObjCPointerCast; - } else { - CK = CK_BitCast; - } - userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK, userExpr); - } - } - MsgExprs.push_back(userExpr); - // We've transferred the ownership to MsgExprs. For now, we *don't* null - // out the argument in the original expression (since we aren't deleting - // the ObjCMessageExpr). See RewritePropertyOrImplicitSetter() usage for more info. - //Exp->setArg(i, 0); - } - // Generate the funky cast. - CastExpr *cast; - SmallVector<QualType, 8> ArgTypes; - QualType returnType; - - // Push 'id' and 'SEL', the 2 implicit arguments. - if (MsgSendFlavor == MsgSendSuperFunctionDecl) - ArgTypes.push_back(Context->getPointerType(getSuperStructType())); - else - ArgTypes.push_back(Context->getObjCIdType()); - ArgTypes.push_back(Context->getObjCSelType()); - if (ObjCMethodDecl *OMD = Exp->getMethodDecl()) { - // Push any user argument types. - for (const auto *PI : OMD->params()) { - QualType t = PI->getType()->isObjCQualifiedIdType() - ? Context->getObjCIdType() - : PI->getType(); - // Make sure we convert "t (^)(...)" to "t (*)(...)". - (void)convertBlockPointerToFunctionPointer(t); - ArgTypes.push_back(t); - } - returnType = Exp->getType(); - convertToUnqualifiedObjCType(returnType); - (void)convertBlockPointerToFunctionPointer(returnType); - } else { - returnType = Context->getObjCIdType(); - } - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = MsgSendFlavor->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, - VK_LValue, SourceLocation()); - - // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid). - // If we don't do this cast, we get the following bizarre warning/note: - // xx.m:13: warning: function called through a non-compatible type - // xx.m:13: note: if this code is reached, the program will abort - cast = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->VoidTy), - CK_BitCast, DRE); - - // Now do the "normal" pointer to function cast. - // If we don't have a method decl, force a variadic cast. - const ObjCMethodDecl *MD = Exp->getMethodDecl(); - QualType castType = - getSimpleFunctionType(returnType, ArgTypes, MD ? MD->isVariadic() : true); - castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, - cast); - - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); - - const FunctionType *FT = msgSendType->getAs<FunctionType>(); - CallExpr *CE = new (Context) - CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc); - Stmt *ReplacingStmt = CE; - if (MsgSendStretFlavor) { - // We have the method which returns a struct/union. Must also generate - // call to objc_msgSend_stret and hang both varieties on a conditional - // expression which dictate which one to envoke depending on size of - // method's return type. - - Expr *STCE = SynthMsgSendStretCallExpr(MsgSendStretFlavor, - returnType, - ArgTypes, MsgExprs, - Exp->getMethodDecl()); - ReplacingStmt = STCE; - } - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return ReplacingStmt; -} - -Stmt *RewriteModernObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { - Stmt *ReplacingStmt = SynthMessageExpr(Exp, Exp->getLocStart(), - Exp->getLocEnd()); - - // Now do the actual rewrite. - ReplaceStmt(Exp, ReplacingStmt); - - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return ReplacingStmt; -} - -// typedef struct objc_object Protocol; -QualType RewriteModernObjC::getProtocolType() { - if (!ProtocolTypeDecl) { - TypeSourceInfo *TInfo - = Context->getTrivialTypeSourceInfo(Context->getObjCIdType()); - ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("Protocol"), - TInfo); - } - return Context->getTypeDeclType(ProtocolTypeDecl); -} - -/// RewriteObjCProtocolExpr - Rewrite a protocol expression into -/// a synthesized/forward data reference (to the protocol's metadata). -/// The forward references (and metadata) are generated in -/// RewriteModernObjC::HandleTranslationUnit(). -Stmt *RewriteModernObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { - std::string Name = "_OBJC_PROTOCOL_REFERENCE_$_" + - Exp->getProtocol()->getNameAsString(); - IdentifierInfo *ID = &Context->Idents.get(Name); - VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), ID, getProtocolType(), - nullptr, SC_Extern); - DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(), - VK_LValue, SourceLocation()); - CastExpr *castExpr = - NoTypeInfoCStyleCastExpr( - Context, Context->getPointerType(DRE->getType()), CK_BitCast, DRE); - ReplaceStmt(Exp, castExpr); - ProtocolExprDecls.insert(Exp->getProtocol()->getCanonicalDecl()); - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return castExpr; - -} - -bool RewriteModernObjC::BufferContainsPPDirectives(const char *startBuf, - const char *endBuf) { - while (startBuf < endBuf) { - if (*startBuf == '#') { - // Skip whitespace. - for (++startBuf; startBuf[0] == ' ' || startBuf[0] == '\t'; ++startBuf) - ; - if (!strncmp(startBuf, "if", strlen("if")) || - !strncmp(startBuf, "ifdef", strlen("ifdef")) || - !strncmp(startBuf, "ifndef", strlen("ifndef")) || - !strncmp(startBuf, "define", strlen("define")) || - !strncmp(startBuf, "undef", strlen("undef")) || - !strncmp(startBuf, "else", strlen("else")) || - !strncmp(startBuf, "elif", strlen("elif")) || - !strncmp(startBuf, "endif", strlen("endif")) || - !strncmp(startBuf, "pragma", strlen("pragma")) || - !strncmp(startBuf, "include", strlen("include")) || - !strncmp(startBuf, "import", strlen("import")) || - !strncmp(startBuf, "include_next", strlen("include_next"))) - return true; - } - startBuf++; - } - return false; -} - -/// IsTagDefinedInsideClass - This routine checks that a named tagged type -/// is defined inside an objective-c class. If so, it returns true. -bool RewriteModernObjC::IsTagDefinedInsideClass(ObjCContainerDecl *IDecl, - TagDecl *Tag, - bool &IsNamedDefinition) { - if (!IDecl) - return false; - SourceLocation TagLocation; - if (RecordDecl *RD = dyn_cast<RecordDecl>(Tag)) { - RD = RD->getDefinition(); - if (!RD || !RD->getDeclName().getAsIdentifierInfo()) - return false; - IsNamedDefinition = true; - TagLocation = RD->getLocation(); - return Context->getSourceManager().isBeforeInTranslationUnit( - IDecl->getLocation(), TagLocation); - } - if (EnumDecl *ED = dyn_cast<EnumDecl>(Tag)) { - if (!ED || !ED->getDeclName().getAsIdentifierInfo()) - return false; - IsNamedDefinition = true; - TagLocation = ED->getLocation(); - return Context->getSourceManager().isBeforeInTranslationUnit( - IDecl->getLocation(), TagLocation); - - } - return false; -} - -/// RewriteObjCFieldDeclType - This routine rewrites a type into the buffer. -/// It handles elaborated types, as well as enum types in the process. -bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type, - std::string &Result) { - if (isa<TypedefType>(Type)) { - Result += "\t"; - return false; - } - - if (Type->isArrayType()) { - QualType ElemTy = Context->getBaseElementType(Type); - return RewriteObjCFieldDeclType(ElemTy, Result); - } - else if (Type->isRecordType()) { - RecordDecl *RD = Type->getAs<RecordType>()->getDecl(); - if (RD->isCompleteDefinition()) { - if (RD->isStruct()) - Result += "\n\tstruct "; - else if (RD->isUnion()) - Result += "\n\tunion "; - else - assert(false && "class not allowed as an ivar type"); - - Result += RD->getName(); - if (GlobalDefinedTags.count(RD)) { - // struct/union is defined globally, use it. - Result += " "; - return true; - } - Result += " {\n"; - for (auto *FD : RD->fields()) - RewriteObjCFieldDecl(FD, Result); - Result += "\t} "; - return true; - } - } - else if (Type->isEnumeralType()) { - EnumDecl *ED = Type->getAs<EnumType>()->getDecl(); - if (ED->isCompleteDefinition()) { - Result += "\n\tenum "; - Result += ED->getName(); - if (GlobalDefinedTags.count(ED)) { - // Enum is globall defined, use it. - Result += " "; - return true; - } - - Result += " {\n"; - for (const auto *EC : ED->enumerators()) { - Result += "\t"; Result += EC->getName(); Result += " = "; - llvm::APSInt Val = EC->getInitVal(); - Result += Val.toString(10); - Result += ",\n"; - } - Result += "\t} "; - return true; - } - } - - Result += "\t"; - convertObjCTypeToCStyleType(Type); - return false; -} - - -/// RewriteObjCFieldDecl - This routine rewrites a field into the buffer. -/// It handles elaborated types, as well as enum types in the process. -void RewriteModernObjC::RewriteObjCFieldDecl(FieldDecl *fieldDecl, - std::string &Result) { - QualType Type = fieldDecl->getType(); - std::string Name = fieldDecl->getNameAsString(); - - bool EleboratedType = RewriteObjCFieldDeclType(Type, Result); - if (!EleboratedType) - Type.getAsStringInternal(Name, Context->getPrintingPolicy()); - Result += Name; - if (fieldDecl->isBitField()) { - Result += " : "; Result += utostr(fieldDecl->getBitWidthValue(*Context)); - } - else if (EleboratedType && Type->isArrayType()) { - const ArrayType *AT = Context->getAsArrayType(Type); - do { - if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) { - Result += "["; - llvm::APInt Dim = CAT->getSize(); - Result += utostr(Dim.getZExtValue()); - Result += "]"; - } - AT = Context->getAsArrayType(AT->getElementType()); - } while (AT); - } - - Result += ";\n"; -} - -/// RewriteLocallyDefinedNamedAggregates - This routine rewrites locally defined -/// named aggregate types into the input buffer. -void RewriteModernObjC::RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDecl, - std::string &Result) { - QualType Type = fieldDecl->getType(); - if (isa<TypedefType>(Type)) - return; - if (Type->isArrayType()) - Type = Context->getBaseElementType(Type); - ObjCContainerDecl *IDecl = - dyn_cast<ObjCContainerDecl>(fieldDecl->getDeclContext()); - - TagDecl *TD = nullptr; - if (Type->isRecordType()) { - TD = Type->getAs<RecordType>()->getDecl(); - } - else if (Type->isEnumeralType()) { - TD = Type->getAs<EnumType>()->getDecl(); - } - - if (TD) { - if (GlobalDefinedTags.count(TD)) - return; - - bool IsNamedDefinition = false; - if (IsTagDefinedInsideClass(IDecl, TD, IsNamedDefinition)) { - RewriteObjCFieldDeclType(Type, Result); - Result += ";"; - } - if (IsNamedDefinition) - GlobalDefinedTags.insert(TD); - } - -} - -unsigned RewriteModernObjC::ObjCIvarBitfieldGroupNo(ObjCIvarDecl *IV) { - const ObjCInterfaceDecl *CDecl = IV->getContainingInterface(); - if (ObjCInterefaceHasBitfieldGroups.count(CDecl)) { - return IvarGroupNumber[IV]; - } - unsigned GroupNo = 0; - SmallVector<const ObjCIvarDecl *, 8> IVars; - for (const ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin(); - IVD; IVD = IVD->getNextIvar()) - IVars.push_back(IVD); - - for (unsigned i = 0, e = IVars.size(); i < e; i++) - if (IVars[i]->isBitField()) { - IvarGroupNumber[IVars[i++]] = ++GroupNo; - while (i < e && IVars[i]->isBitField()) - IvarGroupNumber[IVars[i++]] = GroupNo; - if (i < e) - --i; - } - - ObjCInterefaceHasBitfieldGroups.insert(CDecl); - return IvarGroupNumber[IV]; -} - -QualType RewriteModernObjC::SynthesizeBitfieldGroupStructType( - ObjCIvarDecl *IV, - SmallVectorImpl<ObjCIvarDecl *> &IVars) { - std::string StructTagName; - ObjCIvarBitfieldGroupType(IV, StructTagName); - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, - Context->getTranslationUnitDecl(), - SourceLocation(), SourceLocation(), - &Context->Idents.get(StructTagName)); - for (unsigned i=0, e = IVars.size(); i < e; i++) { - ObjCIvarDecl *Ivar = IVars[i]; - RD->addDecl(FieldDecl::Create(*Context, RD, SourceLocation(), SourceLocation(), - &Context->Idents.get(Ivar->getName()), - Ivar->getType(), - nullptr, /*Expr *BW */Ivar->getBitWidth(), - false, ICIS_NoInit)); - } - RD->completeDefinition(); - return Context->getTagDeclType(RD); -} - -QualType RewriteModernObjC::GetGroupRecordTypeForObjCIvarBitfield(ObjCIvarDecl *IV) { - const ObjCInterfaceDecl *CDecl = IV->getContainingInterface(); - unsigned GroupNo = ObjCIvarBitfieldGroupNo(IV); - std::pair<const ObjCInterfaceDecl*, unsigned> tuple = std::make_pair(CDecl, GroupNo); - if (GroupRecordType.count(tuple)) - return GroupRecordType[tuple]; - - SmallVector<ObjCIvarDecl *, 8> IVars; - for (const ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin(); - IVD; IVD = IVD->getNextIvar()) { - if (IVD->isBitField()) - IVars.push_back(const_cast<ObjCIvarDecl *>(IVD)); - else { - if (!IVars.empty()) { - unsigned GroupNo = ObjCIvarBitfieldGroupNo(IVars[0]); - // Generate the struct type for this group of bitfield ivars. - GroupRecordType[std::make_pair(CDecl, GroupNo)] = - SynthesizeBitfieldGroupStructType(IVars[0], IVars); - IVars.clear(); - } - } - } - if (!IVars.empty()) { - // Do the last one. - unsigned GroupNo = ObjCIvarBitfieldGroupNo(IVars[0]); - GroupRecordType[std::make_pair(CDecl, GroupNo)] = - SynthesizeBitfieldGroupStructType(IVars[0], IVars); - } - QualType RetQT = GroupRecordType[tuple]; - assert(!RetQT.isNull() && "GetGroupRecordTypeForObjCIvarBitfield struct type is NULL"); - - return RetQT; -} - -/// ObjCIvarBitfieldGroupDecl - Names field decl. for ivar bitfield group. -/// Name would be: classname__GRBF_n where n is the group number for this ivar. -void RewriteModernObjC::ObjCIvarBitfieldGroupDecl(ObjCIvarDecl *IV, - std::string &Result) { - const ObjCInterfaceDecl *CDecl = IV->getContainingInterface(); - Result += CDecl->getName(); - Result += "__GRBF_"; - unsigned GroupNo = ObjCIvarBitfieldGroupNo(IV); - Result += utostr(GroupNo); - return; -} - -/// ObjCIvarBitfieldGroupType - Names struct type for ivar bitfield group. -/// Name of the struct would be: classname__T_n where n is the group number for -/// this ivar. -void RewriteModernObjC::ObjCIvarBitfieldGroupType(ObjCIvarDecl *IV, - std::string &Result) { - const ObjCInterfaceDecl *CDecl = IV->getContainingInterface(); - Result += CDecl->getName(); - Result += "__T_"; - unsigned GroupNo = ObjCIvarBitfieldGroupNo(IV); - Result += utostr(GroupNo); - return; -} - -/// ObjCIvarBitfieldGroupOffset - Names symbol for ivar bitfield group field offset. -/// Name would be: OBJC_IVAR_$_classname__GRBF_n where n is the group number for -/// this ivar. -void RewriteModernObjC::ObjCIvarBitfieldGroupOffset(ObjCIvarDecl *IV, - std::string &Result) { - Result += "OBJC_IVAR_$_"; - ObjCIvarBitfieldGroupDecl(IV, Result); -} - -#define SKIP_BITFIELDS(IX, ENDIX, VEC) { \ - while ((IX < ENDIX) && VEC[IX]->isBitField()) \ - ++IX; \ - if (IX < ENDIX) \ - --IX; \ -} - -/// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to -/// an objective-c class with ivars. -void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, - std::string &Result) { - assert(CDecl && "Class missing in SynthesizeObjCInternalStruct"); - assert(CDecl->getName() != "" && - "Name missing in SynthesizeObjCInternalStruct"); - ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass(); - SmallVector<ObjCIvarDecl *, 8> IVars; - for (ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin(); - IVD; IVD = IVD->getNextIvar()) - IVars.push_back(IVD); - - SourceLocation LocStart = CDecl->getLocStart(); - SourceLocation LocEnd = CDecl->getEndOfDefinitionLoc(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - - // If no ivars and no root or if its root, directly or indirectly, - // have no ivars (thus not synthesized) then no need to synthesize this class. - if ((!CDecl->isThisDeclarationADefinition() || IVars.size() == 0) && - (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) { - endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); - ReplaceText(LocStart, endBuf-startBuf, Result); - return; - } - - // Insert named struct/union definitions inside class to - // outer scope. This follows semantics of locally defined - // struct/unions in objective-c classes. - for (unsigned i = 0, e = IVars.size(); i < e; i++) - RewriteLocallyDefinedNamedAggregates(IVars[i], Result); - - // Insert named structs which are syntheized to group ivar bitfields - // to outer scope as well. - for (unsigned i = 0, e = IVars.size(); i < e; i++) - if (IVars[i]->isBitField()) { - ObjCIvarDecl *IV = IVars[i]; - QualType QT = GetGroupRecordTypeForObjCIvarBitfield(IV); - RewriteObjCFieldDeclType(QT, Result); - Result += ";"; - // skip over ivar bitfields in this group. - SKIP_BITFIELDS(i , e, IVars); - } - - Result += "\nstruct "; - Result += CDecl->getNameAsString(); - Result += "_IMPL {\n"; - - if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) { - Result += "\tstruct "; Result += RCDecl->getNameAsString(); - Result += "_IMPL "; Result += RCDecl->getNameAsString(); - Result += "_IVARS;\n"; - } - - for (unsigned i = 0, e = IVars.size(); i < e; i++) { - if (IVars[i]->isBitField()) { - ObjCIvarDecl *IV = IVars[i]; - Result += "\tstruct "; - ObjCIvarBitfieldGroupType(IV, Result); Result += " "; - ObjCIvarBitfieldGroupDecl(IV, Result); Result += ";\n"; - // skip over ivar bitfields in this group. - SKIP_BITFIELDS(i , e, IVars); - } - else - RewriteObjCFieldDecl(IVars[i], Result); - } - - Result += "};\n"; - endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); - ReplaceText(LocStart, endBuf-startBuf, Result); - // Mark this struct as having been generated. - if (!ObjCSynthesizedStructs.insert(CDecl)) - llvm_unreachable("struct already synthesize- RewriteObjCInternalStruct"); -} - -/// RewriteIvarOffsetSymbols - Rewrite ivar offset symbols of those ivars which -/// have been referenced in an ivar access expression. -void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl, - std::string &Result) { - // write out ivar offset symbols which have been referenced in an ivar - // access expression. - llvm::SmallPtrSet<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl]; - if (Ivars.empty()) - return; - - llvm::DenseSet<std::pair<const ObjCInterfaceDecl*, unsigned> > GroupSymbolOutput; - for (llvm::SmallPtrSet<ObjCIvarDecl *, 8>::iterator i = Ivars.begin(), - e = Ivars.end(); i != e; i++) { - ObjCIvarDecl *IvarDecl = (*i); - const ObjCInterfaceDecl *IDecl = IvarDecl->getContainingInterface(); - unsigned GroupNo = 0; - if (IvarDecl->isBitField()) { - GroupNo = ObjCIvarBitfieldGroupNo(IvarDecl); - if (GroupSymbolOutput.count(std::make_pair(IDecl, GroupNo))) - continue; - } - Result += "\n"; - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".objc_ivar$B\")) "; - Result += "extern \"C\" "; - if (LangOpts.MicrosoftExt && - IvarDecl->getAccessControl() != ObjCIvarDecl::Private && - IvarDecl->getAccessControl() != ObjCIvarDecl::Package) - Result += "__declspec(dllimport) "; - - Result += "unsigned long "; - if (IvarDecl->isBitField()) { - ObjCIvarBitfieldGroupOffset(IvarDecl, Result); - GroupSymbolOutput.insert(std::make_pair(IDecl, GroupNo)); - } - else - WriteInternalIvarName(CDecl, IvarDecl, Result); - Result += ";"; - } -} - -//===----------------------------------------------------------------------===// -// Meta Data Emission -//===----------------------------------------------------------------------===// - - -/// RewriteImplementations - This routine rewrites all method implementations -/// and emits meta-data. - -void RewriteModernObjC::RewriteImplementations() { - int ClsDefCount = ClassImplementation.size(); - int CatDefCount = CategoryImplementation.size(); - - // Rewrite implemented methods - for (int i = 0; i < ClsDefCount; i++) { - ObjCImplementationDecl *OIMP = ClassImplementation[i]; - ObjCInterfaceDecl *CDecl = OIMP->getClassInterface(); - if (CDecl->isImplicitInterfaceDecl()) - assert(false && - "Legacy implicit interface rewriting not supported in moder abi"); - RewriteImplementationDecl(OIMP); - } - - for (int i = 0; i < CatDefCount; i++) { - ObjCCategoryImplDecl *CIMP = CategoryImplementation[i]; - ObjCInterfaceDecl *CDecl = CIMP->getClassInterface(); - if (CDecl->isImplicitInterfaceDecl()) - assert(false && - "Legacy implicit interface rewriting not supported in moder abi"); - RewriteImplementationDecl(CIMP); - } -} - -void RewriteModernObjC::RewriteByRefString(std::string &ResultStr, - const std::string &Name, - ValueDecl *VD, bool def) { - assert(BlockByRefDeclNo.count(VD) && - "RewriteByRefString: ByRef decl missing"); - if (def) - ResultStr += "struct "; - ResultStr += "__Block_byref_" + Name + - "_" + utostr(BlockByRefDeclNo[VD]) ; -} - -static bool HasLocalVariableExternalStorage(ValueDecl *VD) { - if (VarDecl *Var = dyn_cast<VarDecl>(VD)) - return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage()); - return false; -} - -std::string RewriteModernObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, - StringRef funcName, - std::string Tag) { - const FunctionType *AFT = CE->getFunctionType(); - QualType RT = AFT->getReturnType(); - std::string StructRef = "struct " + Tag; - SourceLocation BlockLoc = CE->getExprLoc(); - std::string S; - ConvertSourceLocationToLineDirective(BlockLoc, S); - - S += "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" + - funcName.str() + "_block_func_" + utostr(i); - - BlockDecl *BD = CE->getBlockDecl(); - - if (isa<FunctionNoProtoType>(AFT)) { - // No user-supplied arguments. Still need to pass in a pointer to the - // block (to reference imported block decl refs). - S += "(" + StructRef + " *__cself)"; - } else if (BD->param_empty()) { - S += "(" + StructRef + " *__cself)"; - } else { - const FunctionProtoType *FT = cast<FunctionProtoType>(AFT); - assert(FT && "SynthesizeBlockFunc: No function proto"); - S += '('; - // first add the implicit argument. - S += StructRef + " *__cself, "; - std::string ParamStr; - for (BlockDecl::param_iterator AI = BD->param_begin(), - E = BD->param_end(); AI != E; ++AI) { - if (AI != BD->param_begin()) S += ", "; - ParamStr = (*AI)->getNameAsString(); - QualType QT = (*AI)->getType(); - (void)convertBlockPointerToFunctionPointer(QT); - QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy()); - S += ParamStr; - } - if (FT->isVariadic()) { - if (!BD->param_empty()) S += ", "; - S += "..."; - } - S += ')'; - } - S += " {\n"; - - // Create local declarations to avoid rewriting all closure decl ref exprs. - // First, emit a declaration for all "by ref" decls. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - S += " "; - std::string Name = (*I)->getNameAsString(); - std::string TypeString; - RewriteByRefString(TypeString, Name, (*I)); - TypeString += " *"; - Name = TypeString + Name; - S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; - } - // Next, emit a declaration for all "by copy" declarations. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - S += " "; - // Handle nested closure invocation. For example: - // - // void (^myImportedClosure)(void); - // myImportedClosure = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherClosure)(void); - // anotherClosure = ^(void) { - // myImportedClosure(); // import and invoke the closure - // }; - // - if (isTopLevelBlockPointerType((*I)->getType())) { - RewriteBlockPointerTypeVariable(S, (*I)); - S += " = ("; - RewriteBlockPointerType(S, (*I)->getType()); - S += ")"; - S += "__cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; - } - else { - std::string Name = (*I)->getNameAsString(); - QualType QT = (*I)->getType(); - if (HasLocalVariableExternalStorage(*I)) - QT = Context->getPointerType(QT); - QT.getAsStringInternal(Name, Context->getPrintingPolicy()); - S += Name + " = __cself->" + - (*I)->getNameAsString() + "; // bound by copy\n"; - } - } - std::string RewrittenStr = RewrittenBlockExprs[CE]; - const char *cstr = RewrittenStr.c_str(); - while (*cstr++ != '{') ; - S += cstr; - S += "\n"; - return S; -} - -std::string RewriteModernObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - StringRef funcName, - std::string Tag) { - std::string StructRef = "struct " + Tag; - std::string S = "static void __"; - - S += funcName; - S += "_block_copy_" + utostr(i); - S += "(" + StructRef; - S += "*dst, " + StructRef; - S += "*src) {"; - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), - E = ImportedBlockDecls.end(); I != E; ++I) { - ValueDecl *VD = (*I); - S += "_Block_object_assign((void*)&dst->"; - S += (*I)->getNameAsString(); - S += ", (void*)src->"; - S += (*I)->getNameAsString(); - if (BlockByRefDeclsPtrSet.count((*I))) - S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; - else if (VD->getType()->isBlockPointerType()) - S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; - else - S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; - } - S += "}\n"; - - S += "\nstatic void __"; - S += funcName; - S += "_block_dispose_" + utostr(i); - S += "(" + StructRef; - S += "*src) {"; - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), - E = ImportedBlockDecls.end(); I != E; ++I) { - ValueDecl *VD = (*I); - S += "_Block_object_dispose((void*)src->"; - S += (*I)->getNameAsString(); - if (BlockByRefDeclsPtrSet.count((*I))) - S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; - else if (VD->getType()->isBlockPointerType()) - S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; - else - S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; - } - S += "}\n"; - return S; -} - -std::string RewriteModernObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - std::string Desc) { - std::string S = "\nstruct " + Tag; - std::string Constructor = " " + Tag; - - S += " {\n struct __block_impl impl;\n"; - S += " struct " + Desc; - S += "* Desc;\n"; - - Constructor += "(void *fp, "; // Invoke function pointer. - Constructor += "struct " + Desc; // Descriptor pointer. - Constructor += " *desc"; - - if (BlockDeclRefs.size()) { - // Output all "by copy" declarations. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - S += " "; - std::string FieldName = (*I)->getNameAsString(); - std::string ArgName = "_" + FieldName; - // Handle nested closure invocation. For example: - // - // void (^myImportedBlock)(void); - // myImportedBlock = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherBlock)(void); - // anotherBlock = ^(void) { - // myImportedBlock(); // import and invoke the closure - // }; - // - if (isTopLevelBlockPointerType((*I)->getType())) { - S += "struct __block_impl *"; - Constructor += ", void *" + ArgName; - } else { - QualType QT = (*I)->getType(); - if (HasLocalVariableExternalStorage(*I)) - QT = Context->getPointerType(QT); - QT.getAsStringInternal(FieldName, Context->getPrintingPolicy()); - QT.getAsStringInternal(ArgName, Context->getPrintingPolicy()); - Constructor += ", " + ArgName; - } - S += FieldName + ";\n"; - } - // Output all "by ref" declarations. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - S += " "; - std::string FieldName = (*I)->getNameAsString(); - std::string ArgName = "_" + FieldName; - { - std::string TypeString; - RewriteByRefString(TypeString, FieldName, (*I)); - TypeString += " *"; - FieldName = TypeString + FieldName; - ArgName = TypeString + ArgName; - Constructor += ", " + ArgName; - } - S += FieldName + "; // by ref\n"; - } - // Finish writing the constructor. - Constructor += ", int flags=0)"; - // Initialize all "by copy" arguments. - bool firsTime = true; - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); - if (firsTime) { - Constructor += " : "; - firsTime = false; - } - else - Constructor += ", "; - if (isTopLevelBlockPointerType((*I)->getType())) - Constructor += Name + "((struct __block_impl *)_" + Name + ")"; - else - Constructor += Name + "(_" + Name + ")"; - } - // Initialize all "by ref" arguments. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); - if (firsTime) { - Constructor += " : "; - firsTime = false; - } - else - Constructor += ", "; - Constructor += Name + "(_" + Name + "->__forwarding)"; - } - - Constructor += " {\n"; - if (GlobalVarDecl) - Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; - else - Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - - Constructor += " Desc = desc;\n"; - } else { - // Finish writing the constructor. - Constructor += ", int flags=0) {\n"; - if (GlobalVarDecl) - Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; - else - Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - Constructor += " Desc = desc;\n"; - } - Constructor += " "; - Constructor += "}\n"; - S += Constructor; - S += "};\n"; - return S; -} - -std::string RewriteModernObjC::SynthesizeBlockDescriptor(std::string DescTag, - std::string ImplTag, int i, - StringRef FunName, - unsigned hasCopy) { - std::string S = "\nstatic struct " + DescTag; - - S += " {\n size_t reserved;\n"; - S += " size_t Block_size;\n"; - if (hasCopy) { - S += " void (*copy)(struct "; - S += ImplTag; S += "*, struct "; - S += ImplTag; S += "*);\n"; - - S += " void (*dispose)(struct "; - S += ImplTag; S += "*);\n"; - } - S += "} "; - - S += DescTag + "_DATA = { 0, sizeof(struct "; - S += ImplTag + ")"; - if (hasCopy) { - S += ", __" + FunName.str() + "_block_copy_" + utostr(i); - S += ", __" + FunName.str() + "_block_dispose_" + utostr(i); - } - S += "};\n"; - return S; -} - -void RewriteModernObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, - StringRef FunName) { - bool RewriteSC = (GlobalVarDecl && - !Blocks.empty() && - GlobalVarDecl->getStorageClass() == SC_Static && - GlobalVarDecl->getType().getCVRQualifiers()); - if (RewriteSC) { - std::string SC(" void __"); - SC += GlobalVarDecl->getNameAsString(); - SC += "() {}"; - InsertText(FunLocStart, SC); - } - - // Insert closures that were part of the function. - for (unsigned i = 0, count=0; i < Blocks.size(); i++) { - CollectBlockDeclRefInfo(Blocks[i]); - // Need to copy-in the inner copied-in variables not actually used in this - // block. - for (int j = 0; j < InnerDeclRefsCount[i]; j++) { - DeclRefExpr *Exp = InnerDeclRefs[count++]; - ValueDecl *VD = Exp->getDecl(); - BlockDeclRefs.push_back(Exp); - if (!VD->hasAttr<BlocksAttr>()) { - if (!BlockByCopyDeclsPtrSet.count(VD)) { - BlockByCopyDeclsPtrSet.insert(VD); - BlockByCopyDecls.push_back(VD); - } - continue; - } - - if (!BlockByRefDeclsPtrSet.count(VD)) { - BlockByRefDeclsPtrSet.insert(VD); - BlockByRefDecls.push_back(VD); - } - - // imported objects in the inner blocks not used in the outer - // blocks must be copied/disposed in the outer block as well. - if (VD->getType()->isObjCObjectPointerType() || - VD->getType()->isBlockPointerType()) - ImportedBlockDecls.insert(VD); - } - - std::string ImplTag = "__" + FunName.str() + "_block_impl_" + utostr(i); - std::string DescTag = "__" + FunName.str() + "_block_desc_" + utostr(i); - - std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag); - - InsertText(FunLocStart, CI); - - std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag); - - InsertText(FunLocStart, CF); - - if (ImportedBlockDecls.size()) { - std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag); - InsertText(FunLocStart, HF); - } - std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName, - ImportedBlockDecls.size() > 0); - InsertText(FunLocStart, BD); - - BlockDeclRefs.clear(); - BlockByRefDecls.clear(); - BlockByRefDeclsPtrSet.clear(); - BlockByCopyDecls.clear(); - BlockByCopyDeclsPtrSet.clear(); - ImportedBlockDecls.clear(); - } - if (RewriteSC) { - // Must insert any 'const/volatile/static here. Since it has been - // removed as result of rewriting of block literals. - std::string SC; - if (GlobalVarDecl->getStorageClass() == SC_Static) - SC = "static "; - if (GlobalVarDecl->getType().isConstQualified()) - SC += "const "; - if (GlobalVarDecl->getType().isVolatileQualified()) - SC += "volatile "; - if (GlobalVarDecl->getType().isRestrictQualified()) - SC += "restrict "; - InsertText(FunLocStart, SC); - } - if (GlobalConstructionExp) { - // extra fancy dance for global literal expression. - - // Always the latest block expression on the block stack. - std::string Tag = "__"; - Tag += FunName; - Tag += "_block_impl_"; - Tag += utostr(Blocks.size()-1); - std::string globalBuf = "static "; - globalBuf += Tag; globalBuf += " "; - std::string SStr; - - llvm::raw_string_ostream constructorExprBuf(SStr); - GlobalConstructionExp->printPretty(constructorExprBuf, nullptr, - PrintingPolicy(LangOpts)); - globalBuf += constructorExprBuf.str(); - globalBuf += ";\n"; - InsertText(FunLocStart, globalBuf); - GlobalConstructionExp = nullptr; - } - - Blocks.clear(); - InnerDeclRefsCount.clear(); - InnerDeclRefs.clear(); - RewrittenBlockExprs.clear(); -} - -void RewriteModernObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { - SourceLocation FunLocStart = - (!Blocks.empty()) ? getFunctionSourceLocation(*this, FD) - : FD->getTypeSpecStartLoc(); - StringRef FuncName = FD->getName(); - - SynthesizeBlockLiterals(FunLocStart, FuncName); -} - -static void BuildUniqueMethodName(std::string &Name, - ObjCMethodDecl *MD) { - ObjCInterfaceDecl *IFace = MD->getClassInterface(); - Name = IFace->getName(); - Name += "__" + MD->getSelector().getAsString(); - // Convert colons to underscores. - std::string::size_type loc = 0; - while ((loc = Name.find(":", loc)) != std::string::npos) - Name.replace(loc, 1, "_"); -} - -void RewriteModernObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) { - //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n"); - //SourceLocation FunLocStart = MD->getLocStart(); - SourceLocation FunLocStart = MD->getLocStart(); - std::string FuncName; - BuildUniqueMethodName(FuncName, MD); - SynthesizeBlockLiterals(FunLocStart, FuncName); -} - -void RewriteModernObjC::GetBlockDeclRefExprs(Stmt *S) { - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) - GetBlockDeclRefExprs(CBE->getBody()); - else - GetBlockDeclRefExprs(*CI); - } - // Handle specific things. - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) { - if (DRE->refersToEnclosingLocal()) { - // FIXME: Handle enums. - if (!isa<FunctionDecl>(DRE->getDecl())) - BlockDeclRefs.push_back(DRE); - if (HasLocalVariableExternalStorage(DRE->getDecl())) - BlockDeclRefs.push_back(DRE); - } - } - - return; -} - -void RewriteModernObjC::GetInnerBlockDeclRefExprs(Stmt *S, - SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs, - llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts) { - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) { - InnerContexts.insert(cast<DeclContext>(CBE->getBlockDecl())); - GetInnerBlockDeclRefExprs(CBE->getBody(), - InnerBlockDeclRefs, - InnerContexts); - } - else - GetInnerBlockDeclRefExprs(*CI, - InnerBlockDeclRefs, - InnerContexts); - - } - // Handle specific things. - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) { - if (DRE->refersToEnclosingLocal()) { - if (!isa<FunctionDecl>(DRE->getDecl()) && - !InnerContexts.count(DRE->getDecl()->getDeclContext())) - InnerBlockDeclRefs.push_back(DRE); - if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) - if (Var->isFunctionOrMethodVarDecl()) - ImportedLocalExternalDecls.insert(Var); - } - } - - return; -} - -/// convertObjCTypeToCStyleType - This routine converts such objc types -/// as qualified objects, and blocks to their closest c/c++ types that -/// it can. It returns true if input type was modified. -bool RewriteModernObjC::convertObjCTypeToCStyleType(QualType &T) { - QualType oldT = T; - convertBlockPointerToFunctionPointer(T); - if (T->isFunctionPointerType()) { - QualType PointeeTy; - if (const PointerType* PT = T->getAs<PointerType>()) { - PointeeTy = PT->getPointeeType(); - if (const FunctionType *FT = PointeeTy->getAs<FunctionType>()) { - T = convertFunctionTypeOfBlocks(FT); - T = Context->getPointerType(T); - } - } - } - - convertToUnqualifiedObjCType(T); - return T != oldT; -} - -/// convertFunctionTypeOfBlocks - This routine converts a function type -/// whose result type may be a block pointer or whose argument type(s) -/// might be block pointers to an equivalent function type replacing -/// all block pointers to function pointers. -QualType RewriteModernObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) { - const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT); - // FTP will be null for closures that don't take arguments. - // Generate a funky cast. - SmallVector<QualType, 8> ArgTypes; - QualType Res = FT->getReturnType(); - bool modified = convertObjCTypeToCStyleType(Res); - - if (FTP) { - for (auto &I : FTP->param_types()) { - QualType t = I; - // Make sure we convert "t (^)(...)" to "t (*)(...)". - if (convertObjCTypeToCStyleType(t)) - modified = true; - ArgTypes.push_back(t); - } - } - QualType FuncType; - if (modified) - FuncType = getSimpleFunctionType(Res, ArgTypes); - else FuncType = QualType(FT, 0); - return FuncType; -} - -Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { - // Navigate to relevant type information. - const BlockPointerType *CPT = nullptr; - - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BlockExp)) { - CPT = DRE->getType()->getAs<BlockPointerType>(); - } else if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(BlockExp)) { - CPT = MExpr->getType()->getAs<BlockPointerType>(); - } - else if (const ParenExpr *PRE = dyn_cast<ParenExpr>(BlockExp)) { - return SynthesizeBlockCall(Exp, PRE->getSubExpr()); - } - else if (const ImplicitCastExpr *IEXPR = dyn_cast<ImplicitCastExpr>(BlockExp)) - CPT = IEXPR->getType()->getAs<BlockPointerType>(); - else if (const ConditionalOperator *CEXPR = - dyn_cast<ConditionalOperator>(BlockExp)) { - Expr *LHSExp = CEXPR->getLHS(); - Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp); - Expr *RHSExp = CEXPR->getRHS(); - Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp); - Expr *CONDExp = CEXPR->getCond(); - ConditionalOperator *CondExpr = - new (Context) ConditionalOperator(CONDExp, - SourceLocation(), cast<Expr>(LHSStmt), - SourceLocation(), cast<Expr>(RHSStmt), - Exp->getType(), VK_RValue, OK_Ordinary); - return CondExpr; - } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) { - CPT = IRE->getType()->getAs<BlockPointerType>(); - } else if (const PseudoObjectExpr *POE - = dyn_cast<PseudoObjectExpr>(BlockExp)) { - CPT = POE->getType()->castAs<BlockPointerType>(); - } else { - assert(1 && "RewriteBlockClass: Bad type"); - } - assert(CPT && "RewriteBlockClass: Bad type"); - const FunctionType *FT = CPT->getPointeeType()->getAs<FunctionType>(); - assert(FT && "RewriteBlockClass: Bad type"); - const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT); - // FTP will be null for closures that don't take arguments. - - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("__block_impl")); - QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD)); - - // Generate a funky cast. - SmallVector<QualType, 8> ArgTypes; - - // Push the block argument type. - ArgTypes.push_back(PtrBlock); - if (FTP) { - for (auto &I : FTP->param_types()) { - QualType t = I; - // Make sure we convert "t (^)(...)" to "t (*)(...)". - if (!convertBlockPointerToFunctionPointer(t)) - convertToUnqualifiedObjCType(t); - ArgTypes.push_back(t); - } - } - // Now do the pointer to function cast. - QualType PtrToFuncCastType = getSimpleFunctionType(Exp->getType(), ArgTypes); - - PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType); - - CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock, - CK_BitCast, - const_cast<Expr*>(BlockExp)); - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - BlkCast); - //PE->dump(); - - FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), - SourceLocation(), - &Context->Idents.get("FuncPtr"), - Context->VoidPtrTy, nullptr, - /*BitWidth=*/nullptr, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), - FD->getType(), VK_LValue, - OK_Ordinary); - - - CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType, - CK_BitCast, ME); - PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast); - - SmallVector<Expr*, 8> BlkExprs; - // Add the implicit argument. - BlkExprs.push_back(BlkCast); - // Add the user arguments. - for (CallExpr::arg_iterator I = Exp->arg_begin(), - E = Exp->arg_end(); I != E; ++I) { - BlkExprs.push_back(*I); - } - CallExpr *CE = new (Context) CallExpr(*Context, PE, BlkExprs, - Exp->getType(), VK_RValue, - SourceLocation()); - return CE; -} - -// We need to return the rewritten expression to handle cases where the -// DeclRefExpr is embedded in another expression being rewritten. -// For example: -// -// int main() { -// __block Foo *f; -// __block int i; -// -// void (^myblock)() = ^() { -// [f test]; // f is a DeclRefExpr embedded in a message (which is being rewritten). -// i = 77; -// }; -//} -Stmt *RewriteModernObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { - // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR - // for each DeclRefExp where BYREFVAR is name of the variable. - ValueDecl *VD = DeclRefExp->getDecl(); - bool isArrow = DeclRefExp->refersToEnclosingLocal(); - - FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), - SourceLocation(), - &Context->Idents.get("__forwarding"), - Context->VoidPtrTy, nullptr, - /*BitWidth=*/nullptr, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, - FD, SourceLocation(), - FD->getType(), VK_LValue, - OK_Ordinary); - - StringRef Name = VD->getName(); - FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(), - &Context->Idents.get(Name), - Context->VoidPtrTy, nullptr, - /*BitWidth=*/nullptr, /*Mutable=*/true, - ICIS_NoInit); - ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), - DeclRefExp->getType(), VK_LValue, OK_Ordinary); - - - - // Need parens to enforce precedence. - ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(), - DeclRefExp->getExprLoc(), - ME); - ReplaceStmt(DeclRefExp, PE); - return PE; -} - -// Rewrites the imported local variable V with external storage -// (static, extern, etc.) as *V -// -Stmt *RewriteModernObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) { - ValueDecl *VD = DRE->getDecl(); - if (VarDecl *Var = dyn_cast<VarDecl>(VD)) - if (!ImportedLocalExternalDecls.count(Var)) - return DRE; - Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(), - VK_LValue, OK_Ordinary, - DRE->getLocation()); - // Need parens to enforce precedence. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - Exp); - ReplaceStmt(DRE, PE); - return PE; -} - -void RewriteModernObjC::RewriteCastExpr(CStyleCastExpr *CE) { - SourceLocation LocStart = CE->getLParenLoc(); - SourceLocation LocEnd = CE->getRParenLoc(); - - // Need to avoid trying to rewrite synthesized casts. - if (LocStart.isInvalid()) - return; - // Need to avoid trying to rewrite casts contained in macros. - if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd)) - return; - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - QualType QT = CE->getType(); - const Type* TypePtr = QT->getAs<Type>(); - if (isa<TypeOfExprType>(TypePtr)) { - const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr); - QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); - std::string TypeAsString = "("; - RewriteBlockPointerType(TypeAsString, QT); - TypeAsString += ")"; - ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString); - return; - } - // advance the location to startArgList. - const char *argPtr = startBuf; - - while (*argPtr++ && (argPtr < endBuf)) { - switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - LocStart = LocStart.getLocWithOffset(argPtr-startBuf); - ReplaceText(LocStart, 1, "*"); - break; - } - } - return; -} - -void RewriteModernObjC::RewriteImplicitCastObjCExpr(CastExpr *IC) { - CastKind CastKind = IC->getCastKind(); - if (CastKind != CK_BlockPointerToObjCPointerCast && - CastKind != CK_AnyPointerToBlockPointerCast) - return; - - QualType QT = IC->getType(); - (void)convertBlockPointerToFunctionPointer(QT); - std::string TypeString(QT.getAsString(Context->getPrintingPolicy())); - std::string Str = "("; - Str += TypeString; - Str += ")"; - InsertText(IC->getSubExpr()->getLocStart(), &Str[0], Str.size()); - - return; -} - -void RewriteModernObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { - SourceLocation DeclLoc = FD->getLocation(); - unsigned parenCount = 0; - - // We have 1 or more arguments that have closure pointers. - const char *startBuf = SM->getCharacterData(DeclLoc); - const char *startArgList = strchr(startBuf, '('); - - assert((*startArgList == '(') && "Rewriter fuzzy parser confused"); - - parenCount++; - // advance the location to startArgList. - DeclLoc = DeclLoc.getLocWithOffset(startArgList-startBuf); - assert((DeclLoc.isValid()) && "Invalid DeclLoc"); - - const char *argPtr = startArgList; - - while (*argPtr++ && parenCount) { - switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - DeclLoc = DeclLoc.getLocWithOffset(argPtr-startArgList); - ReplaceText(DeclLoc, 1, "*"); - break; - case '(': - parenCount++; - break; - case ')': - parenCount--; - break; - } - } - return; -} - -bool RewriteModernObjC::PointerTypeTakesAnyBlockArguments(QualType QT) { - const FunctionProtoType *FTP; - const PointerType *PT = QT->getAs<PointerType>(); - if (PT) { - FTP = PT->getPointeeType()->getAs<FunctionProtoType>(); - } else { - const BlockPointerType *BPT = QT->getAs<BlockPointerType>(); - assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); - FTP = BPT->getPointeeType()->getAs<FunctionProtoType>(); - } - if (FTP) { - for (const auto &I : FTP->param_types()) - if (isTopLevelBlockPointerType(I)) - return true; - } - return false; -} - -bool RewriteModernObjC::PointerTypeTakesAnyObjCQualifiedType(QualType QT) { - const FunctionProtoType *FTP; - const PointerType *PT = QT->getAs<PointerType>(); - if (PT) { - FTP = PT->getPointeeType()->getAs<FunctionProtoType>(); - } else { - const BlockPointerType *BPT = QT->getAs<BlockPointerType>(); - assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); - FTP = BPT->getPointeeType()->getAs<FunctionProtoType>(); - } - if (FTP) { - for (const auto &I : FTP->param_types()) { - if (I->isObjCQualifiedIdType()) - return true; - if (I->isObjCObjectPointerType() && - I->getPointeeType()->isObjCQualifiedInterfaceType()) - return true; - } - - } - return false; -} - -void RewriteModernObjC::GetExtentOfArgList(const char *Name, const char *&LParen, - const char *&RParen) { - const char *argPtr = strchr(Name, '('); - assert((*argPtr == '(') && "Rewriter fuzzy parser confused"); - - LParen = argPtr; // output the start. - argPtr++; // skip past the left paren. - unsigned parenCount = 1; - - while (*argPtr && parenCount) { - switch (*argPtr) { - case '(': parenCount++; break; - case ')': parenCount--; break; - default: break; - } - if (parenCount) argPtr++; - } - assert((*argPtr == ')') && "Rewriter fuzzy parser confused"); - RParen = argPtr; // output the end -} - -void RewriteModernObjC::RewriteBlockPointerDecl(NamedDecl *ND) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { - RewriteBlockPointerFunctionArgs(FD); - return; - } - // Handle Variables and Typedefs. - SourceLocation DeclLoc = ND->getLocation(); - QualType DeclT; - if (VarDecl *VD = dyn_cast<VarDecl>(ND)) - DeclT = VD->getType(); - else if (TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(ND)) - DeclT = TDD->getUnderlyingType(); - else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND)) - DeclT = FD->getType(); - else - llvm_unreachable("RewriteBlockPointerDecl(): Decl type not yet handled"); - - const char *startBuf = SM->getCharacterData(DeclLoc); - const char *endBuf = startBuf; - // scan backward (from the decl location) for the end of the previous decl. - while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart) - startBuf--; - SourceLocation Start = DeclLoc.getLocWithOffset(startBuf-endBuf); - std::string buf; - unsigned OrigLength=0; - // *startBuf != '^' if we are dealing with a pointer to function that - // may take block argument types (which will be handled below). - if (*startBuf == '^') { - // Replace the '^' with '*', computing a negative offset. - buf = '*'; - startBuf++; - OrigLength++; - } - while (*startBuf != ')') { - buf += *startBuf; - startBuf++; - OrigLength++; - } - buf += ')'; - OrigLength++; - - if (PointerTypeTakesAnyBlockArguments(DeclT) || - PointerTypeTakesAnyObjCQualifiedType(DeclT)) { - // Replace the '^' with '*' for arguments. - // Replace id<P> with id/*<>*/ - DeclLoc = ND->getLocation(); - startBuf = SM->getCharacterData(DeclLoc); - const char *argListBegin, *argListEnd; - GetExtentOfArgList(startBuf, argListBegin, argListEnd); - while (argListBegin < argListEnd) { - if (*argListBegin == '^') - buf += '*'; - else if (*argListBegin == '<') { - buf += "/*"; - buf += *argListBegin++; - OrigLength++; - while (*argListBegin != '>') { - buf += *argListBegin++; - OrigLength++; - } - buf += *argListBegin; - buf += "*/"; - } - else - buf += *argListBegin; - argListBegin++; - OrigLength++; - } - buf += ')'; - OrigLength++; - } - ReplaceText(Start, OrigLength, buf); - - return; -} - - -/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes: -/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst, -/// struct Block_byref_id_object *src) { -/// _Block_object_assign (&_dest->object, _src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT -/// [|BLOCK_FIELD_IS_WEAK]) // object -/// _Block_object_assign(&_dest->object, _src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK -/// [|BLOCK_FIELD_IS_WEAK]) // block -/// } -/// And: -/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) { -/// _Block_object_dispose(_src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT -/// [|BLOCK_FIELD_IS_WEAK]) // object -/// _Block_object_dispose(_src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK -/// [|BLOCK_FIELD_IS_WEAK]) // block -/// } - -std::string RewriteModernObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD, - int flag) { - std::string S; - if (CopyDestroyCache.count(flag)) - return S; - CopyDestroyCache.insert(flag); - S = "static void __Block_byref_id_object_copy_"; - S += utostr(flag); - S += "(void *dst, void *src) {\n"; - - // offset into the object pointer is computed as: - // void * + void* + int + int + void* + void * - unsigned IntSize = - static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); - unsigned VoidPtrSize = - static_cast<unsigned>(Context->getTypeSize(Context->VoidPtrTy)); - - unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/Context->getCharWidth(); - S += " _Block_object_assign((char*)dst + "; - S += utostr(offset); - S += ", *(void * *) ((char*)src + "; - S += utostr(offset); - S += "), "; - S += utostr(flag); - S += ");\n}\n"; - - S += "static void __Block_byref_id_object_dispose_"; - S += utostr(flag); - S += "(void *src) {\n"; - S += " _Block_object_dispose(*(void * *) ((char*)src + "; - S += utostr(offset); - S += "), "; - S += utostr(flag); - S += ");\n}\n"; - return S; -} - -/// RewriteByRefVar - For each __block typex ND variable this routine transforms -/// the declaration into: -/// struct __Block_byref_ND { -/// void *__isa; // NULL for everything except __weak pointers -/// struct __Block_byref_ND *__forwarding; -/// int32_t __flags; -/// int32_t __size; -/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object -/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object -/// typex ND; -/// }; -/// -/// It then replaces declaration of ND variable with: -/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag, -/// __size=sizeof(struct __Block_byref_ND), -/// ND=initializer-if-any}; -/// -/// -void RewriteModernObjC::RewriteByRefVar(VarDecl *ND, bool firstDecl, - bool lastDecl) { - int flag = 0; - int isa = 0; - SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); - if (DeclLoc.isInvalid()) - // If type location is missing, it is because of missing type (a warning). - // Use variable's location which is good for this case. - DeclLoc = ND->getLocation(); - const char *startBuf = SM->getCharacterData(DeclLoc); - SourceLocation X = ND->getLocEnd(); - X = SM->getExpansionLoc(X); - const char *endBuf = SM->getCharacterData(X); - std::string Name(ND->getNameAsString()); - std::string ByrefType; - RewriteByRefString(ByrefType, Name, ND, true); - ByrefType += " {\n"; - ByrefType += " void *__isa;\n"; - RewriteByRefString(ByrefType, Name, ND); - ByrefType += " *__forwarding;\n"; - ByrefType += " int __flags;\n"; - ByrefType += " int __size;\n"; - // Add void *__Block_byref_id_object_copy; - // void *__Block_byref_id_object_dispose; if needed. - QualType Ty = ND->getType(); - bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty, ND); - if (HasCopyAndDispose) { - ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n"; - ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n"; - } - - QualType T = Ty; - (void)convertBlockPointerToFunctionPointer(T); - T.getAsStringInternal(Name, Context->getPrintingPolicy()); - - ByrefType += " " + Name + ";\n"; - ByrefType += "};\n"; - // Insert this type in global scope. It is needed by helper function. - SourceLocation FunLocStart; - if (CurFunctionDef) - FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef); - else { - assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null"); - FunLocStart = CurMethodDef->getLocStart(); - } - InsertText(FunLocStart, ByrefType); - - if (Ty.isObjCGCWeak()) { - flag |= BLOCK_FIELD_IS_WEAK; - isa = 1; - } - if (HasCopyAndDispose) { - flag = BLOCK_BYREF_CALLER; - QualType Ty = ND->getType(); - // FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well. - if (Ty->isBlockPointerType()) - flag |= BLOCK_FIELD_IS_BLOCK; - else - flag |= BLOCK_FIELD_IS_OBJECT; - std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag); - if (!HF.empty()) - Preamble += HF; - } - - // struct __Block_byref_ND ND = - // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND), - // initializer-if-any}; - bool hasInit = (ND->getInit() != nullptr); - // FIXME. rewriter does not support __block c++ objects which - // require construction. - if (hasInit) - if (CXXConstructExpr *CExp = dyn_cast<CXXConstructExpr>(ND->getInit())) { - CXXConstructorDecl *CXXDecl = CExp->getConstructor(); - if (CXXDecl && CXXDecl->isDefaultConstructor()) - hasInit = false; - } - - unsigned flags = 0; - if (HasCopyAndDispose) - flags |= BLOCK_HAS_COPY_DISPOSE; - Name = ND->getNameAsString(); - ByrefType.clear(); - RewriteByRefString(ByrefType, Name, ND); - std::string ForwardingCastType("("); - ForwardingCastType += ByrefType + " *)"; - ByrefType += " " + Name + " = {(void*)"; - ByrefType += utostr(isa); - ByrefType += "," + ForwardingCastType + "&" + Name + ", "; - ByrefType += utostr(flags); - ByrefType += ", "; - ByrefType += "sizeof("; - RewriteByRefString(ByrefType, Name, ND); - ByrefType += ")"; - if (HasCopyAndDispose) { - ByrefType += ", __Block_byref_id_object_copy_"; - ByrefType += utostr(flag); - ByrefType += ", __Block_byref_id_object_dispose_"; - ByrefType += utostr(flag); - } - - if (!firstDecl) { - // In multiple __block declarations, and for all but 1st declaration, - // find location of the separating comma. This would be start location - // where new text is to be inserted. - DeclLoc = ND->getLocation(); - const char *startDeclBuf = SM->getCharacterData(DeclLoc); - const char *commaBuf = startDeclBuf; - while (*commaBuf != ',') - commaBuf--; - assert((*commaBuf == ',') && "RewriteByRefVar: can't find ','"); - DeclLoc = DeclLoc.getLocWithOffset(commaBuf - startDeclBuf); - startBuf = commaBuf; - } - - if (!hasInit) { - ByrefType += "};\n"; - unsigned nameSize = Name.size(); - // for block or function pointer declaration. Name is aleady - // part of the declaration. - if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) - nameSize = 1; - ReplaceText(DeclLoc, endBuf-startBuf+nameSize, ByrefType); - } - else { - ByrefType += ", "; - SourceLocation startLoc; - Expr *E = ND->getInit(); - if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) - startLoc = ECE->getLParenLoc(); - else - startLoc = E->getLocStart(); - startLoc = SM->getExpansionLoc(startLoc); - endBuf = SM->getCharacterData(startLoc); - ReplaceText(DeclLoc, endBuf-startBuf, ByrefType); - - const char separator = lastDecl ? ';' : ','; - const char *startInitializerBuf = SM->getCharacterData(startLoc); - const char *separatorBuf = strchr(startInitializerBuf, separator); - assert((*separatorBuf == separator) && - "RewriteByRefVar: can't find ';' or ','"); - SourceLocation separatorLoc = - startLoc.getLocWithOffset(separatorBuf-startInitializerBuf); - - InsertText(separatorLoc, lastDecl ? "}" : "};\n"); - } - return; -} - -void RewriteModernObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { - // Add initializers for any closure decl refs. - GetBlockDeclRefExprs(Exp->getBody()); - if (BlockDeclRefs.size()) { - // Unique all "by copy" declarations. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (!BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>()) { - if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { - BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); - BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl()); - } - } - // Unique all "by ref" declarations. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>()) { - if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { - BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); - BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl()); - } - } - // Find any imported blocks...they will need special attention. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>() || - BlockDeclRefs[i]->getType()->isObjCObjectPointerType() || - BlockDeclRefs[i]->getType()->isBlockPointerType()) - ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl()); - } -} - -FunctionDecl *RewriteModernObjC::SynthBlockInitFunctionDecl(StringRef name) { - IdentifierInfo *ID = &Context->Idents.get(name); - QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy); - return FunctionDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), ID, FType, nullptr, SC_Extern, - false, false); -} - -Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp, - const SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs) { - - const BlockDecl *block = Exp->getBlockDecl(); - - Blocks.push_back(Exp); - - CollectBlockDeclRefInfo(Exp); - - // Add inner imported variables now used in current block. - int countOfInnerDecls = 0; - if (!InnerBlockDeclRefs.empty()) { - for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) { - DeclRefExpr *Exp = InnerBlockDeclRefs[i]; - ValueDecl *VD = Exp->getDecl(); - if (!VD->hasAttr<BlocksAttr>() && !BlockByCopyDeclsPtrSet.count(VD)) { - // We need to save the copied-in variables in nested - // blocks because it is needed at the end for some of the API generations. - // See SynthesizeBlockLiterals routine. - InnerDeclRefs.push_back(Exp); countOfInnerDecls++; - BlockDeclRefs.push_back(Exp); - BlockByCopyDeclsPtrSet.insert(VD); - BlockByCopyDecls.push_back(VD); - } - if (VD->hasAttr<BlocksAttr>() && !BlockByRefDeclsPtrSet.count(VD)) { - InnerDeclRefs.push_back(Exp); countOfInnerDecls++; - BlockDeclRefs.push_back(Exp); - BlockByRefDeclsPtrSet.insert(VD); - BlockByRefDecls.push_back(VD); - } - } - // Find any imported blocks...they will need special attention. - for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) - if (InnerBlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>() || - InnerBlockDeclRefs[i]->getType()->isObjCObjectPointerType() || - InnerBlockDeclRefs[i]->getType()->isBlockPointerType()) - ImportedBlockDecls.insert(InnerBlockDeclRefs[i]->getDecl()); - } - InnerDeclRefsCount.push_back(countOfInnerDecls); - - std::string FuncName; - - if (CurFunctionDef) - FuncName = CurFunctionDef->getNameAsString(); - else if (CurMethodDef) - BuildUniqueMethodName(FuncName, CurMethodDef); - else if (GlobalVarDecl) - FuncName = std::string(GlobalVarDecl->getNameAsString()); - - bool GlobalBlockExpr = - block->getDeclContext()->getRedeclContext()->isFileContext(); - - if (GlobalBlockExpr && !GlobalVarDecl) { - Diags.Report(block->getLocation(), GlobalBlockRewriteFailedDiag); - GlobalBlockExpr = false; - } - - std::string BlockNumber = utostr(Blocks.size()-1); - - std::string Func = "__" + FuncName + "_block_func_" + BlockNumber; - - // Get a pointer to the function type so we can cast appropriately. - QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType()); - QualType FType = Context->getPointerType(BFT); - - FunctionDecl *FD; - Expr *NewRep; - - // Simulate a constructor call... - std::string Tag; - - if (GlobalBlockExpr) - Tag = "__global_"; - else - Tag = "__"; - Tag += FuncName + "_block_impl_" + BlockNumber; - - FD = SynthBlockInitFunctionDecl(Tag); - DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, FType, VK_RValue, - SourceLocation()); - - SmallVector<Expr*, 4> InitExprs; - - // Initialize the block function. - FD = SynthBlockInitFunctionDecl(Func); - DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, false, FD->getType(), - VK_LValue, SourceLocation()); - CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, - CK_BitCast, Arg); - InitExprs.push_back(castExpr); - - // Initialize the block descriptor. - std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA"; - - VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get(DescData.c_str()), - Context->VoidPtrTy, nullptr, - SC_Static); - UnaryOperator *DescRefExpr = - new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false, - Context->VoidPtrTy, - VK_LValue, - SourceLocation()), - UO_AddrOf, - Context->getPointerType(Context->VoidPtrTy), - VK_RValue, OK_Ordinary, - SourceLocation()); - InitExprs.push_back(DescRefExpr); - - // Add initializers for any closure decl refs. - if (BlockDeclRefs.size()) { - Expr *Exp; - // Output all "by copy" declarations. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - if (isObjCType((*I)->getType())) { - // FIXME: Conform to ABI ([[obj retain] autorelease]). - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), - VK_LValue, SourceLocation()); - if (HasLocalVariableExternalStorage(*I)) { - QualType QT = (*I)->getType(); - QT = Context->getPointerType(QT); - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, - OK_Ordinary, SourceLocation()); - } - } else if (isTopLevelBlockPointerType((*I)->getType())) { - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Arg = new (Context) DeclRefExpr(FD, false, FD->getType(), - VK_LValue, SourceLocation()); - Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, - CK_BitCast, Arg); - } else { - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), - VK_LValue, SourceLocation()); - if (HasLocalVariableExternalStorage(*I)) { - QualType QT = (*I)->getType(); - QT = Context->getPointerType(QT); - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, - OK_Ordinary, SourceLocation()); - } - - } - InitExprs.push_back(Exp); - } - // Output all "by ref" declarations. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - ValueDecl *ND = (*I); - std::string Name(ND->getNameAsString()); - std::string RecName; - RewriteByRefString(RecName, Name, ND, true); - IdentifierInfo *II = &Context->Idents.get(RecName.c_str() - + sizeof("struct")); - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - II); - assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl"); - QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, - SourceLocation()); - bool isNestedCapturedVar = false; - if (block) - for (const auto &CI : block->captures()) { - const VarDecl *variable = CI.getVariable(); - if (variable == ND && CI.isNested()) { - assert (CI.isByRef() && - "SynthBlockInitExpr - captured block variable is not byref"); - isNestedCapturedVar = true; - break; - } - } - // captured nested byref variable has its address passed. Do not take - // its address again. - if (!isNestedCapturedVar) - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, - Context->getPointerType(Exp->getType()), - VK_RValue, OK_Ordinary, SourceLocation()); - Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); - InitExprs.push_back(Exp); - } - } - if (ImportedBlockDecls.size()) { - // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR - int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR); - unsigned IntSize = - static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); - Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag), - Context->IntTy, SourceLocation()); - InitExprs.push_back(FlagExp); - } - NewRep = new (Context) CallExpr(*Context, DRE, InitExprs, - FType, VK_LValue, SourceLocation()); - - if (GlobalBlockExpr) { - assert (!GlobalConstructionExp && - "SynthBlockInitExpr - GlobalConstructionExp must be null"); - GlobalConstructionExp = NewRep; - NewRep = DRE; - } - - NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, - Context->getPointerType(NewRep->getType()), - VK_RValue, OK_Ordinary, SourceLocation()); - NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, - NewRep); - BlockDeclRefs.clear(); - BlockByRefDecls.clear(); - BlockByRefDeclsPtrSet.clear(); - BlockByCopyDecls.clear(); - BlockByCopyDeclsPtrSet.clear(); - ImportedBlockDecls.clear(); - return NewRep; -} - -bool RewriteModernObjC::IsDeclStmtInForeachHeader(DeclStmt *DS) { - if (const ObjCForCollectionStmt * CS = - dyn_cast<ObjCForCollectionStmt>(Stmts.back())) - return CS->getElement() == DS; - return false; -} - -//===----------------------------------------------------------------------===// -// Function Body / Expression rewriting -//===----------------------------------------------------------------------===// - -Stmt *RewriteModernObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { - if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || - isa<DoStmt>(S) || isa<ForStmt>(S)) - Stmts.push_back(S); - else if (isa<ObjCForCollectionStmt>(S)) { - Stmts.push_back(S); - ObjCBcLabelNo.push_back(++BcLabelCount); - } - - // Pseudo-object operations and ivar references need special - // treatment because we're going to recursively rewrite them. - if (PseudoObjectExpr *PseudoOp = dyn_cast<PseudoObjectExpr>(S)) { - if (isa<BinaryOperator>(PseudoOp->getSyntacticForm())) { - return RewritePropertyOrImplicitSetter(PseudoOp); - } else { - return RewritePropertyOrImplicitGetter(PseudoOp); - } - } else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) { - return RewriteObjCIvarRefExpr(IvarRefExpr); - } - else if (isa<OpaqueValueExpr>(S)) - S = cast<OpaqueValueExpr>(S)->getSourceExpr(); - - SourceRange OrigStmtRange = S->getSourceRange(); - - // Perform a bottom up rewrite of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - Stmt *childStmt = (*CI); - Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(childStmt); - if (newStmt) { - *CI = newStmt; - } - } - - if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) { - SmallVector<DeclRefExpr *, 8> InnerBlockDeclRefs; - llvm::SmallPtrSet<const DeclContext *, 8> InnerContexts; - InnerContexts.insert(BE->getBlockDecl()); - ImportedLocalExternalDecls.clear(); - GetInnerBlockDeclRefExprs(BE->getBody(), - InnerBlockDeclRefs, InnerContexts); - // Rewrite the block body in place. - Stmt *SaveCurrentBody = CurrentBody; - CurrentBody = BE->getBody(); - PropParentMap = nullptr; - // block literal on rhs of a property-dot-sytax assignment - // must be replaced by its synthesize ast so getRewrittenText - // works as expected. In this case, what actually ends up on RHS - // is the blockTranscribed which is the helper function for the - // block literal; as in: self.c = ^() {[ace ARR];}; - bool saveDisableReplaceStmt = DisableReplaceStmt; - DisableReplaceStmt = false; - RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); - DisableReplaceStmt = saveDisableReplaceStmt; - CurrentBody = SaveCurrentBody; - PropParentMap = nullptr; - ImportedLocalExternalDecls.clear(); - // Now we snarf the rewritten text and stash it away for later use. - std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); - RewrittenBlockExprs[BE] = Str; - - Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs); - - //blockTranscribed->dump(); - ReplaceStmt(S, blockTranscribed); - return blockTranscribed; - } - // Handle specific things. - if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S)) - return RewriteAtEncode(AtEncode); - - if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S)) - return RewriteAtSelector(AtSelector); - - if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S)) - return RewriteObjCStringLiteral(AtString); - - if (ObjCBoolLiteralExpr *BoolLitExpr = dyn_cast<ObjCBoolLiteralExpr>(S)) - return RewriteObjCBoolLiteralExpr(BoolLitExpr); - - if (ObjCBoxedExpr *BoxedExpr = dyn_cast<ObjCBoxedExpr>(S)) - return RewriteObjCBoxedExpr(BoxedExpr); - - if (ObjCArrayLiteral *ArrayLitExpr = dyn_cast<ObjCArrayLiteral>(S)) - return RewriteObjCArrayLiteralExpr(ArrayLitExpr); - - if (ObjCDictionaryLiteral *DictionaryLitExpr = - dyn_cast<ObjCDictionaryLiteral>(S)) - return RewriteObjCDictionaryLiteralExpr(DictionaryLitExpr); - - if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) { -#if 0 - // Before we rewrite it, put the original message expression in a comment. - SourceLocation startLoc = MessExpr->getLocStart(); - SourceLocation endLoc = MessExpr->getLocEnd(); - - const char *startBuf = SM->getCharacterData(startLoc); - const char *endBuf = SM->getCharacterData(endLoc); - - std::string messString; - messString += "// "; - messString.append(startBuf, endBuf-startBuf+1); - messString += "\n"; - - // FIXME: Missing definition of - // InsertText(clang::SourceLocation, char const*, unsigned int). - // InsertText(startLoc, messString.c_str(), messString.size()); - // Tried this, but it didn't work either... - // ReplaceText(startLoc, 0, messString.c_str(), messString.size()); -#endif - return RewriteMessageExpr(MessExpr); - } - - if (ObjCAutoreleasePoolStmt *StmtAutoRelease = - dyn_cast<ObjCAutoreleasePoolStmt>(S)) { - return RewriteObjCAutoreleasePoolStmt(StmtAutoRelease); - } - - if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S)) - return RewriteObjCTryStmt(StmtTry); - - if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S)) - return RewriteObjCSynchronizedStmt(StmtTry); - - if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S)) - return RewriteObjCThrowStmt(StmtThrow); - - if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S)) - return RewriteObjCProtocolExpr(ProtocolExp); - - if (ObjCForCollectionStmt *StmtForCollection = - dyn_cast<ObjCForCollectionStmt>(S)) - return RewriteObjCForCollectionStmt(StmtForCollection, - OrigStmtRange.getEnd()); - if (BreakStmt *StmtBreakStmt = - dyn_cast<BreakStmt>(S)) - return RewriteBreakStmt(StmtBreakStmt); - if (ContinueStmt *StmtContinueStmt = - dyn_cast<ContinueStmt>(S)) - return RewriteContinueStmt(StmtContinueStmt); - - // Need to check for protocol refs (id <P>, Foo <P> *) in variable decls - // and cast exprs. - if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) { - // FIXME: What we're doing here is modifying the type-specifier that - // precedes the first Decl. In the future the DeclGroup should have - // a separate type-specifier that we can rewrite. - // NOTE: We need to avoid rewriting the DeclStmt if it is within - // the context of an ObjCForCollectionStmt. For example: - // NSArray *someArray; - // for (id <FooProtocol> index in someArray) ; - // This is because RewriteObjCForCollectionStmt() does textual rewriting - // and it depends on the original text locations/positions. - if (Stmts.empty() || !IsDeclStmtInForeachHeader(DS)) - RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin()); - - // Blocks rewrite rules. - for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); - DI != DE; ++DI) { - Decl *SD = *DI; - if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) { - if (isTopLevelBlockPointerType(ND->getType())) - RewriteBlockPointerDecl(ND); - else if (ND->getType()->isFunctionPointerType()) - CheckFunctionPointerDecl(ND->getType(), ND); - if (VarDecl *VD = dyn_cast<VarDecl>(SD)) { - if (VD->hasAttr<BlocksAttr>()) { - static unsigned uniqueByrefDeclCount = 0; - assert(!BlockByRefDeclNo.count(ND) && - "RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl"); - BlockByRefDeclNo[ND] = uniqueByrefDeclCount++; - RewriteByRefVar(VD, (DI == DS->decl_begin()), ((DI+1) == DE)); - } - else - RewriteTypeOfDecl(VD); - } - } - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) { - if (isTopLevelBlockPointerType(TD->getUnderlyingType())) - RewriteBlockPointerDecl(TD); - else if (TD->getUnderlyingType()->isFunctionPointerType()) - CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - } - } - } - - if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S)) - RewriteObjCQualifiedInterfaceTypes(CE); - - if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || - isa<DoStmt>(S) || isa<ForStmt>(S)) { - assert(!Stmts.empty() && "Statement stack is empty"); - assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) || - isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back())) - && "Statement stack mismatch"); - Stmts.pop_back(); - } - // Handle blocks rewriting. - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) { - ValueDecl *VD = DRE->getDecl(); - if (VD->hasAttr<BlocksAttr>()) - return RewriteBlockDeclRefExpr(DRE); - if (HasLocalVariableExternalStorage(VD)) - return RewriteLocalVariableExternalStorage(DRE); - } - - if (CallExpr *CE = dyn_cast<CallExpr>(S)) { - if (CE->getCallee()->getType()->isBlockPointerType()) { - Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee()); - ReplaceStmt(S, BlockCall); - return BlockCall; - } - } - if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S)) { - RewriteCastExpr(CE); - } - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) { - RewriteImplicitCastObjCExpr(ICE); - } -#if 0 - - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) { - CastExpr *Replacement = new (Context) CastExpr(ICE->getType(), - ICE->getSubExpr(), - SourceLocation()); - // Get the new text. - std::string SStr; - llvm::raw_string_ostream Buf(SStr); - Replacement->printPretty(Buf); - const std::string &Str = Buf.str(); - - printf("CAST = %s\n", &Str[0]); - InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size()); - delete S; - return Replacement; - } -#endif - // Return this stmt unmodified. - return S; -} - -void RewriteModernObjC::RewriteRecordBody(RecordDecl *RD) { - for (auto *FD : RD->fields()) { - if (isTopLevelBlockPointerType(FD->getType())) - RewriteBlockPointerDecl(FD); - if (FD->getType()->isObjCQualifiedIdType() || - FD->getType()->isObjCQualifiedInterfaceType()) - RewriteObjCQualifiedInterfaceTypes(FD); - } -} - -/// HandleDeclInMainFile - This is called for each top-level decl defined in the -/// main file of the input. -void RewriteModernObjC::HandleDeclInMainFile(Decl *D) { - switch (D->getKind()) { - case Decl::Function: { - FunctionDecl *FD = cast<FunctionDecl>(D); - if (FD->isOverloadedOperator()) - return; - - // Since function prototypes don't have ParmDecl's, we check the function - // prototype. This enables us to rewrite function declarations and - // definitions using the same code. - RewriteBlocksInFunctionProtoType(FD->getType(), FD); - - if (!FD->isThisDeclarationADefinition()) - break; - - // FIXME: If this should support Obj-C++, support CXXTryStmt - if (CompoundStmt *Body = dyn_cast_or_null<CompoundStmt>(FD->getBody())) { - CurFunctionDef = FD; - CurrentBody = Body; - Body = - cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body)); - FD->setBody(Body); - CurrentBody = nullptr; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = nullptr; - } - // This synthesizes and inserts the block "impl" struct, invoke function, - // and any copy/dispose helper functions. - InsertBlockLiteralsWithinFunction(FD); - RewriteLineDirective(D); - CurFunctionDef = nullptr; - } - break; - } - case Decl::ObjCMethod: { - ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D); - if (CompoundStmt *Body = MD->getCompoundBody()) { - CurMethodDef = MD; - CurrentBody = Body; - Body = - cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body)); - MD->setBody(Body); - CurrentBody = nullptr; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = nullptr; - } - InsertBlockLiteralsWithinMethod(MD); - RewriteLineDirective(D); - CurMethodDef = nullptr; - } - break; - } - case Decl::ObjCImplementation: { - ObjCImplementationDecl *CI = cast<ObjCImplementationDecl>(D); - ClassImplementation.push_back(CI); - break; - } - case Decl::ObjCCategoryImpl: { - ObjCCategoryImplDecl *CI = cast<ObjCCategoryImplDecl>(D); - CategoryImplementation.push_back(CI); - break; - } - case Decl::Var: { - VarDecl *VD = cast<VarDecl>(D); - RewriteObjCQualifiedInterfaceTypes(VD); - if (isTopLevelBlockPointerType(VD->getType())) - RewriteBlockPointerDecl(VD); - else if (VD->getType()->isFunctionPointerType()) { - CheckFunctionPointerDecl(VD->getType(), VD); - if (VD->getInit()) { - if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) { - RewriteCastExpr(CE); - } - } - } else if (VD->getType()->isRecordType()) { - RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl(); - if (RD->isCompleteDefinition()) - RewriteRecordBody(RD); - } - if (VD->getInit()) { - GlobalVarDecl = VD; - CurrentBody = VD->getInit(); - RewriteFunctionBodyOrGlobalInitializer(VD->getInit()); - CurrentBody = nullptr; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = nullptr; - } - SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName()); - GlobalVarDecl = nullptr; - - // This is needed for blocks. - if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) { - RewriteCastExpr(CE); - } - } - break; - } - case Decl::TypeAlias: - case Decl::Typedef: { - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { - if (isTopLevelBlockPointerType(TD->getUnderlyingType())) - RewriteBlockPointerDecl(TD); - else if (TD->getUnderlyingType()->isFunctionPointerType()) - CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - else - RewriteObjCQualifiedInterfaceTypes(TD); - } - break; - } - case Decl::CXXRecord: - case Decl::Record: { - RecordDecl *RD = cast<RecordDecl>(D); - if (RD->isCompleteDefinition()) - RewriteRecordBody(RD); - break; - } - default: - break; - } - // Nothing yet. -} - -/// Write_ProtocolExprReferencedMetadata - This routine writer out the -/// protocol reference symbols in the for of: -/// struct _protocol_t *PROTOCOL_REF = &PROTOCOL_METADATA. -static void Write_ProtocolExprReferencedMetadata(ASTContext *Context, - ObjCProtocolDecl *PDecl, - std::string &Result) { - // Also output .objc_protorefs$B section and its meta-data. - if (Context->getLangOpts().MicrosoftExt) - Result += "static "; - Result += "struct _protocol_t *"; - Result += "_OBJC_PROTOCOL_REFERENCE_$_"; - Result += PDecl->getNameAsString(); - Result += " = &"; - Result += "_OBJC_PROTOCOL_"; Result += PDecl->getNameAsString(); - Result += ";\n"; -} - -void RewriteModernObjC::HandleTranslationUnit(ASTContext &C) { - if (Diags.hasErrorOccurred()) - return; - - RewriteInclude(); - - for (unsigned i = 0, e = FunctionDefinitionsSeen.size(); i < e; i++) { - // translation of function bodies were postponed until all class and - // their extensions and implementations are seen. This is because, we - // cannot build grouping structs for bitfields until they are all seen. - FunctionDecl *FDecl = FunctionDefinitionsSeen[i]; - HandleTopLevelSingleDecl(FDecl); - } - - // Here's a great place to add any extra declarations that may be needed. - // Write out meta data for each @protocol(<expr>). - for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(), - E = ProtocolExprDecls.end(); I != E; ++I) { - RewriteObjCProtocolMetaData(*I, Preamble); - Write_ProtocolExprReferencedMetadata(Context, (*I), Preamble); - } - - InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false); - - if (ClassImplementation.size() || CategoryImplementation.size()) - RewriteImplementations(); - - for (unsigned i = 0, e = ObjCInterfacesSeen.size(); i < e; i++) { - ObjCInterfaceDecl *CDecl = ObjCInterfacesSeen[i]; - // Write struct declaration for the class matching its ivar declarations. - // Note that for modern abi, this is postponed until the end of TU - // because class extensions and the implementation might declare their own - // private ivars. - RewriteInterfaceDecl(CDecl); - } - - // Get the buffer corresponding to MainFileID. If we haven't changed it, then - // we are done. - if (const RewriteBuffer *RewriteBuf = - Rewrite.getRewriteBufferFor(MainFileID)) { - //printf("Changed:\n"); - *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); - } else { - llvm::errs() << "No changes\n"; - } - - if (ClassImplementation.size() || CategoryImplementation.size() || - ProtocolExprDecls.size()) { - // Rewrite Objective-c meta data* - std::string ResultStr; - RewriteMetaDataIntoBuffer(ResultStr); - // Emit metadata. - *OutFile << ResultStr; - } - // Emit ImageInfo; - { - std::string ResultStr; - WriteImageInfo(ResultStr); - *OutFile << ResultStr; - } - OutFile->flush(); -} - -void RewriteModernObjC::Initialize(ASTContext &context) { - InitializeCommon(context); - - Preamble += "#ifndef __OBJC2__\n"; - Preamble += "#define __OBJC2__\n"; - Preamble += "#endif\n"; - - // declaring objc_selector outside the parameter list removes a silly - // scope related warning... - if (IsHeader) - Preamble = "#pragma once\n"; - Preamble += "struct objc_selector; struct objc_class;\n"; - Preamble += "struct __rw_objc_super { \n\tstruct objc_object *object; "; - Preamble += "\n\tstruct objc_object *superClass; "; - // Add a constructor for creating temporary objects. - Preamble += "\n\t__rw_objc_super(struct objc_object *o, struct objc_object *s) "; - Preamble += ": object(o), superClass(s) {} "; - Preamble += "\n};\n"; - - if (LangOpts.MicrosoftExt) { - // Define all sections using syntax that makes sense. - // These are currently generated. - Preamble += "\n#pragma section(\".objc_classlist$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_catlist$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_imageinfo$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_nlclslist$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_nlcatlist$B\", long, read, write)\n"; - // These are generated but not necessary for functionality. - Preamble += "#pragma section(\".cat_cls_meth$B\", long, read, write)\n"; - Preamble += "#pragma section(\".inst_meth$B\", long, read, write)\n"; - Preamble += "#pragma section(\".cls_meth$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_ivar$B\", long, read, write)\n"; - - // These need be generated for performance. Currently they are not, - // using API calls instead. - Preamble += "#pragma section(\".objc_selrefs$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_classrefs$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_superrefs$B\", long, read, write)\n"; - - } - Preamble += "#ifndef _REWRITER_typedef_Protocol\n"; - Preamble += "typedef struct objc_object Protocol;\n"; - Preamble += "#define _REWRITER_typedef_Protocol\n"; - Preamble += "#endif\n"; - if (LangOpts.MicrosoftExt) { - Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n"; - Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n"; - } - else - Preamble += "#define __OBJC_RW_DLLIMPORT extern\n"; - - Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSend(void);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSendSuper(void);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSend_stret(void);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSendSuper_stret(void);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSend_fpret(void);\n"; - - Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *objc_getClass"; - Preamble += "(const char *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass"; - Preamble += "(struct objc_class *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *objc_getMetaClass"; - Preamble += "(const char *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw( struct objc_object *);\n"; - // @synchronized hooks. - Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_enter( struct objc_object *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_exit( struct objc_object *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n"; - Preamble += "#ifdef _WIN64\n"; - Preamble += "typedef unsigned long long _WIN_NSUInteger;\n"; - Preamble += "#else\n"; - Preamble += "typedef unsigned int _WIN_NSUInteger;\n"; - Preamble += "#endif\n"; - Preamble += "#ifndef __FASTENUMERATIONSTATE\n"; - Preamble += "struct __objcFastEnumerationState {\n\t"; - Preamble += "unsigned long state;\n\t"; - Preamble += "void **itemsPtr;\n\t"; - Preamble += "unsigned long *mutationsPtr;\n\t"; - Preamble += "unsigned long extra[5];\n};\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n"; - Preamble += "#define __FASTENUMERATIONSTATE\n"; - Preamble += "#endif\n"; - Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n"; - Preamble += "struct __NSConstantStringImpl {\n"; - Preamble += " int *isa;\n"; - Preamble += " int flags;\n"; - Preamble += " char *str;\n"; - Preamble += "#if _WIN64\n"; - Preamble += " long long length;\n"; - Preamble += "#else\n"; - Preamble += " long length;\n"; - Preamble += "#endif\n"; - Preamble += "};\n"; - Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n"; - Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n"; - Preamble += "#else\n"; - Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n"; - Preamble += "#endif\n"; - Preamble += "#define __NSCONSTANTSTRINGIMPL\n"; - Preamble += "#endif\n"; - // Blocks preamble. - Preamble += "#ifndef BLOCK_IMPL\n"; - Preamble += "#define BLOCK_IMPL\n"; - Preamble += "struct __block_impl {\n"; - Preamble += " void *isa;\n"; - Preamble += " int Flags;\n"; - Preamble += " int Reserved;\n"; - Preamble += " void *FuncPtr;\n"; - Preamble += "};\n"; - Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n"; - Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n"; - Preamble += "extern \"C\" __declspec(dllexport) " - "void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n"; - Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n"; - Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n"; - Preamble += "#else\n"; - Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n"; - Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n"; - Preamble += "#endif\n"; - Preamble += "#endif\n"; - if (LangOpts.MicrosoftExt) { - Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; - Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; - Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests. - Preamble += "#define __attribute__(X)\n"; - Preamble += "#endif\n"; - Preamble += "#ifndef __weak\n"; - Preamble += "#define __weak\n"; - Preamble += "#endif\n"; - Preamble += "#ifndef __block\n"; - Preamble += "#define __block\n"; - Preamble += "#endif\n"; - } - else { - Preamble += "#define __block\n"; - Preamble += "#define __weak\n"; - } - - // Declarations required for modern objective-c array and dictionary literals. - Preamble += "\n#include <stdarg.h>\n"; - Preamble += "struct __NSContainer_literal {\n"; - Preamble += " void * *arr;\n"; - Preamble += " __NSContainer_literal (unsigned int count, ...) {\n"; - Preamble += "\tva_list marker;\n"; - Preamble += "\tva_start(marker, count);\n"; - Preamble += "\tarr = new void *[count];\n"; - Preamble += "\tfor (unsigned i = 0; i < count; i++)\n"; - Preamble += "\t arr[i] = va_arg(marker, void *);\n"; - Preamble += "\tva_end( marker );\n"; - Preamble += " };\n"; - Preamble += " ~__NSContainer_literal() {\n"; - Preamble += "\tdelete[] arr;\n"; - Preamble += " }\n"; - Preamble += "};\n"; - - // Declaration required for implementation of @autoreleasepool statement. - Preamble += "extern \"C\" __declspec(dllimport) void * objc_autoreleasePoolPush(void);\n"; - Preamble += "extern \"C\" __declspec(dllimport) void objc_autoreleasePoolPop(void *);\n\n"; - Preamble += "struct __AtAutoreleasePool {\n"; - Preamble += " __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}\n"; - Preamble += " ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}\n"; - Preamble += " void * atautoreleasepoolobj;\n"; - Preamble += "};\n"; - - // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long - // as this avoids warning in any 64bit/32bit compilation model. - Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n"; -} - -/// RewriteIvarOffsetComputation - This rutine synthesizes computation of -/// ivar offset. -void RewriteModernObjC::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, - std::string &Result) { - Result += "__OFFSETOFIVAR__(struct "; - Result += ivar->getContainingInterface()->getNameAsString(); - if (LangOpts.MicrosoftExt) - Result += "_IMPL"; - Result += ", "; - if (ivar->isBitField()) - ObjCIvarBitfieldGroupDecl(ivar, Result); - else - Result += ivar->getNameAsString(); - Result += ")"; -} - -/// WriteModernMetadataDeclarations - Writes out metadata declarations for modern ABI. -/// struct _prop_t { -/// const char *name; -/// char *attributes; -/// } - -/// struct _prop_list_t { -/// uint32_t entsize; // sizeof(struct _prop_t) -/// uint32_t count_of_properties; -/// struct _prop_t prop_list[count_of_properties]; -/// } - -/// struct _protocol_t; - -/// struct _protocol_list_t { -/// long protocol_count; // Note, this is 32/64 bit -/// struct _protocol_t * protocol_list[protocol_count]; -/// } - -/// struct _objc_method { -/// SEL _cmd; -/// const char *method_type; -/// char *_imp; -/// } - -/// struct _method_list_t { -/// uint32_t entsize; // sizeof(struct _objc_method) -/// uint32_t method_count; -/// struct _objc_method method_list[method_count]; -/// } - -/// struct _protocol_t { -/// id isa; // NULL -/// const char *protocol_name; -/// const struct _protocol_list_t * protocol_list; // super protocols -/// const struct method_list_t *instance_methods; -/// const struct method_list_t *class_methods; -/// const struct method_list_t *optionalInstanceMethods; -/// const struct method_list_t *optionalClassMethods; -/// const struct _prop_list_t * properties; -/// const uint32_t size; // sizeof(struct _protocol_t) -/// const uint32_t flags; // = 0 -/// const char ** extendedMethodTypes; -/// } - -/// struct _ivar_t { -/// unsigned long int *offset; // pointer to ivar offset location -/// const char *name; -/// const char *type; -/// uint32_t alignment; -/// uint32_t size; -/// } - -/// struct _ivar_list_t { -/// uint32 entsize; // sizeof(struct _ivar_t) -/// uint32 count; -/// struct _ivar_t list[count]; -/// } - -/// struct _class_ro_t { -/// uint32_t flags; -/// uint32_t instanceStart; -/// uint32_t instanceSize; -/// uint32_t reserved; // only when building for 64bit targets -/// const uint8_t *ivarLayout; -/// const char *name; -/// const struct _method_list_t *baseMethods; -/// const struct _protocol_list_t *baseProtocols; -/// const struct _ivar_list_t *ivars; -/// const uint8_t *weakIvarLayout; -/// const struct _prop_list_t *properties; -/// } - -/// struct _class_t { -/// struct _class_t *isa; -/// struct _class_t *superclass; -/// void *cache; -/// IMP *vtable; -/// struct _class_ro_t *ro; -/// } - -/// struct _category_t { -/// const char *name; -/// struct _class_t *cls; -/// const struct _method_list_t *instance_methods; -/// const struct _method_list_t *class_methods; -/// const struct _protocol_list_t *protocols; -/// const struct _prop_list_t *properties; -/// } - -/// MessageRefTy - LLVM for: -/// struct _message_ref_t { -/// IMP messenger; -/// SEL name; -/// }; - -/// SuperMessageRefTy - LLVM for: -/// struct _super_message_ref_t { -/// SUPER_IMP messenger; -/// SEL name; -/// }; - -static void WriteModernMetadataDeclarations(ASTContext *Context, std::string &Result) { - static bool meta_data_declared = false; - if (meta_data_declared) - return; - - Result += "\nstruct _prop_t {\n"; - Result += "\tconst char *name;\n"; - Result += "\tconst char *attributes;\n"; - Result += "};\n"; - - Result += "\nstruct _protocol_t;\n"; - - Result += "\nstruct _objc_method {\n"; - Result += "\tstruct objc_selector * _cmd;\n"; - Result += "\tconst char *method_type;\n"; - Result += "\tvoid *_imp;\n"; - Result += "};\n"; - - Result += "\nstruct _protocol_t {\n"; - Result += "\tvoid * isa; // NULL\n"; - Result += "\tconst char *protocol_name;\n"; - Result += "\tconst struct _protocol_list_t * protocol_list; // super protocols\n"; - Result += "\tconst struct method_list_t *instance_methods;\n"; - Result += "\tconst struct method_list_t *class_methods;\n"; - Result += "\tconst struct method_list_t *optionalInstanceMethods;\n"; - Result += "\tconst struct method_list_t *optionalClassMethods;\n"; - Result += "\tconst struct _prop_list_t * properties;\n"; - Result += "\tconst unsigned int size; // sizeof(struct _protocol_t)\n"; - Result += "\tconst unsigned int flags; // = 0\n"; - Result += "\tconst char ** extendedMethodTypes;\n"; - Result += "};\n"; - - Result += "\nstruct _ivar_t {\n"; - Result += "\tunsigned long int *offset; // pointer to ivar offset location\n"; - Result += "\tconst char *name;\n"; - Result += "\tconst char *type;\n"; - Result += "\tunsigned int alignment;\n"; - Result += "\tunsigned int size;\n"; - Result += "};\n"; - - Result += "\nstruct _class_ro_t {\n"; - Result += "\tunsigned int flags;\n"; - Result += "\tunsigned int instanceStart;\n"; - Result += "\tunsigned int instanceSize;\n"; - const llvm::Triple &Triple(Context->getTargetInfo().getTriple()); - if (Triple.getArch() == llvm::Triple::x86_64) - Result += "\tunsigned int reserved;\n"; - Result += "\tconst unsigned char *ivarLayout;\n"; - Result += "\tconst char *name;\n"; - Result += "\tconst struct _method_list_t *baseMethods;\n"; - Result += "\tconst struct _objc_protocol_list *baseProtocols;\n"; - Result += "\tconst struct _ivar_list_t *ivars;\n"; - Result += "\tconst unsigned char *weakIvarLayout;\n"; - Result += "\tconst struct _prop_list_t *properties;\n"; - Result += "};\n"; - - Result += "\nstruct _class_t {\n"; - Result += "\tstruct _class_t *isa;\n"; - Result += "\tstruct _class_t *superclass;\n"; - Result += "\tvoid *cache;\n"; - Result += "\tvoid *vtable;\n"; - Result += "\tstruct _class_ro_t *ro;\n"; - Result += "};\n"; - - Result += "\nstruct _category_t {\n"; - Result += "\tconst char *name;\n"; - Result += "\tstruct _class_t *cls;\n"; - Result += "\tconst struct _method_list_t *instance_methods;\n"; - Result += "\tconst struct _method_list_t *class_methods;\n"; - Result += "\tconst struct _protocol_list_t *protocols;\n"; - Result += "\tconst struct _prop_list_t *properties;\n"; - Result += "};\n"; - - Result += "extern \"C\" __declspec(dllimport) struct objc_cache _objc_empty_cache;\n"; - Result += "#pragma warning(disable:4273)\n"; - meta_data_declared = true; -} - -static void Write_protocol_list_t_TypeDecl(std::string &Result, - long super_protocol_count) { - Result += "struct /*_protocol_list_t*/"; Result += " {\n"; - Result += "\tlong protocol_count; // Note, this is 32/64 bit\n"; - Result += "\tstruct _protocol_t *super_protocols["; - Result += utostr(super_protocol_count); Result += "];\n"; - Result += "}"; -} - -static void Write_method_list_t_TypeDecl(std::string &Result, - unsigned int method_count) { - Result += "struct /*_method_list_t*/"; Result += " {\n"; - Result += "\tunsigned int entsize; // sizeof(struct _objc_method)\n"; - Result += "\tunsigned int method_count;\n"; - Result += "\tstruct _objc_method method_list["; - Result += utostr(method_count); Result += "];\n"; - Result += "}"; -} - -static void Write__prop_list_t_TypeDecl(std::string &Result, - unsigned int property_count) { - Result += "struct /*_prop_list_t*/"; Result += " {\n"; - Result += "\tunsigned int entsize; // sizeof(struct _prop_t)\n"; - Result += "\tunsigned int count_of_properties;\n"; - Result += "\tstruct _prop_t prop_list["; - Result += utostr(property_count); Result += "];\n"; - Result += "}"; -} - -static void Write__ivar_list_t_TypeDecl(std::string &Result, - unsigned int ivar_count) { - Result += "struct /*_ivar_list_t*/"; Result += " {\n"; - Result += "\tunsigned int entsize; // sizeof(struct _prop_t)\n"; - Result += "\tunsigned int count;\n"; - Result += "\tstruct _ivar_t ivar_list["; - Result += utostr(ivar_count); Result += "];\n"; - Result += "}"; -} - -static void Write_protocol_list_initializer(ASTContext *Context, std::string &Result, - ArrayRef<ObjCProtocolDecl *> SuperProtocols, - StringRef VarName, - StringRef ProtocolName) { - if (SuperProtocols.size() > 0) { - Result += "\nstatic "; - Write_protocol_list_t_TypeDecl(Result, SuperProtocols.size()); - Result += " "; Result += VarName; - Result += ProtocolName; - Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; - Result += "\t"; Result += utostr(SuperProtocols.size()); Result += ",\n"; - for (unsigned i = 0, e = SuperProtocols.size(); i < e; i++) { - ObjCProtocolDecl *SuperPD = SuperProtocols[i]; - Result += "\t&"; Result += "_OBJC_PROTOCOL_"; - Result += SuperPD->getNameAsString(); - if (i == e-1) - Result += "\n};\n"; - else - Result += ",\n"; - } - } -} - -static void Write_method_list_t_initializer(RewriteModernObjC &RewriteObj, - ASTContext *Context, std::string &Result, - ArrayRef<ObjCMethodDecl *> Methods, - StringRef VarName, - StringRef TopLevelDeclName, - bool MethodImpl) { - if (Methods.size() > 0) { - Result += "\nstatic "; - Write_method_list_t_TypeDecl(Result, Methods.size()); - Result += " "; Result += VarName; - Result += TopLevelDeclName; - Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; - Result += "\t"; Result += "sizeof(_objc_method)"; Result += ",\n"; - Result += "\t"; Result += utostr(Methods.size()); Result += ",\n"; - for (unsigned i = 0, e = Methods.size(); i < e; i++) { - ObjCMethodDecl *MD = Methods[i]; - if (i == 0) - Result += "\t{{(struct objc_selector *)\""; - else - Result += "\t{(struct objc_selector *)\""; - Result += (MD)->getSelector().getAsString(); Result += "\""; - Result += ", "; - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl(MD, MethodTypeString); - Result += "\""; Result += MethodTypeString; Result += "\""; - Result += ", "; - if (!MethodImpl) - Result += "0"; - else { - Result += "(void *)"; - Result += RewriteObj.MethodInternalNames[MD]; - } - if (i == e-1) - Result += "}}\n"; - else - Result += "},\n"; - } - Result += "};\n"; - } -} - -static void Write_prop_list_t_initializer(RewriteModernObjC &RewriteObj, - ASTContext *Context, std::string &Result, - ArrayRef<ObjCPropertyDecl *> Properties, - const Decl *Container, - StringRef VarName, - StringRef ProtocolName) { - if (Properties.size() > 0) { - Result += "\nstatic "; - Write__prop_list_t_TypeDecl(Result, Properties.size()); - Result += " "; Result += VarName; - Result += ProtocolName; - Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; - Result += "\t"; Result += "sizeof(_prop_t)"; Result += ",\n"; - Result += "\t"; Result += utostr(Properties.size()); Result += ",\n"; - for (unsigned i = 0, e = Properties.size(); i < e; i++) { - ObjCPropertyDecl *PropDecl = Properties[i]; - if (i == 0) - Result += "\t{{\""; - else - Result += "\t{\""; - Result += PropDecl->getName(); Result += "\","; - std::string PropertyTypeString, QuotePropertyTypeString; - Context->getObjCEncodingForPropertyDecl(PropDecl, Container, PropertyTypeString); - RewriteObj.QuoteDoublequotes(PropertyTypeString, QuotePropertyTypeString); - Result += "\""; Result += QuotePropertyTypeString; Result += "\""; - if (i == e-1) - Result += "}}\n"; - else - Result += "},\n"; - } - Result += "};\n"; - } -} - -// Metadata flags -enum MetaDataDlags { - CLS = 0x0, - CLS_META = 0x1, - CLS_ROOT = 0x2, - OBJC2_CLS_HIDDEN = 0x10, - CLS_EXCEPTION = 0x20, - - /// (Obsolete) ARC-specific: this class has a .release_ivars method - CLS_HAS_IVAR_RELEASER = 0x40, - /// class was compiled with -fobjc-arr - CLS_COMPILED_BY_ARC = 0x80 // (1<<7) -}; - -static void Write__class_ro_t_initializer(ASTContext *Context, std::string &Result, - unsigned int flags, - const std::string &InstanceStart, - const std::string &InstanceSize, - ArrayRef<ObjCMethodDecl *>baseMethods, - ArrayRef<ObjCProtocolDecl *>baseProtocols, - ArrayRef<ObjCIvarDecl *>ivars, - ArrayRef<ObjCPropertyDecl *>Properties, - StringRef VarName, - StringRef ClassName) { - Result += "\nstatic struct _class_ro_t "; - Result += VarName; Result += ClassName; - Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; - Result += "\t"; - Result += llvm::utostr(flags); Result += ", "; - Result += InstanceStart; Result += ", "; - Result += InstanceSize; Result += ", \n"; - Result += "\t"; - const llvm::Triple &Triple(Context->getTargetInfo().getTriple()); - if (Triple.getArch() == llvm::Triple::x86_64) - // uint32_t const reserved; // only when building for 64bit targets - Result += "(unsigned int)0, \n\t"; - // const uint8_t * const ivarLayout; - Result += "0, \n\t"; - Result += "\""; Result += ClassName; Result += "\",\n\t"; - bool metaclass = ((flags & CLS_META) != 0); - if (baseMethods.size() > 0) { - Result += "(const struct _method_list_t *)&"; - if (metaclass) - Result += "_OBJC_$_CLASS_METHODS_"; - else - Result += "_OBJC_$_INSTANCE_METHODS_"; - Result += ClassName; - Result += ",\n\t"; - } - else - Result += "0, \n\t"; - - if (!metaclass && baseProtocols.size() > 0) { - Result += "(const struct _objc_protocol_list *)&"; - Result += "_OBJC_CLASS_PROTOCOLS_$_"; Result += ClassName; - Result += ",\n\t"; - } - else - Result += "0, \n\t"; - - if (!metaclass && ivars.size() > 0) { - Result += "(const struct _ivar_list_t *)&"; - Result += "_OBJC_$_INSTANCE_VARIABLES_"; Result += ClassName; - Result += ",\n\t"; - } - else - Result += "0, \n\t"; - - // weakIvarLayout - Result += "0, \n\t"; - if (!metaclass && Properties.size() > 0) { - Result += "(const struct _prop_list_t *)&"; - Result += "_OBJC_$_PROP_LIST_"; Result += ClassName; - Result += ",\n"; - } - else - Result += "0, \n"; - - Result += "};\n"; -} - -static void Write_class_t(ASTContext *Context, std::string &Result, - StringRef VarName, - const ObjCInterfaceDecl *CDecl, bool metaclass) { - bool rootClass = (!CDecl->getSuperClass()); - const ObjCInterfaceDecl *RootClass = CDecl; - - if (!rootClass) { - // Find the Root class - RootClass = CDecl->getSuperClass(); - while (RootClass->getSuperClass()) { - RootClass = RootClass->getSuperClass(); - } - } - - if (metaclass && rootClass) { - // Need to handle a case of use of forward declaration. - Result += "\n"; - Result += "extern \"C\" "; - if (CDecl->getImplementation()) - Result += "__declspec(dllexport) "; - else - Result += "__declspec(dllimport) "; - - Result += "struct _class_t OBJC_CLASS_$_"; - Result += CDecl->getNameAsString(); - Result += ";\n"; - } - // Also, for possibility of 'super' metadata class not having been defined yet. - if (!rootClass) { - ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass(); - Result += "\n"; - Result += "extern \"C\" "; - if (SuperClass->getImplementation()) - Result += "__declspec(dllexport) "; - else - Result += "__declspec(dllimport) "; - - Result += "struct _class_t "; - Result += VarName; - Result += SuperClass->getNameAsString(); - Result += ";\n"; - - if (metaclass && RootClass != SuperClass) { - Result += "extern \"C\" "; - if (RootClass->getImplementation()) - Result += "__declspec(dllexport) "; - else - Result += "__declspec(dllimport) "; - - Result += "struct _class_t "; - Result += VarName; - Result += RootClass->getNameAsString(); - Result += ";\n"; - } - } - - Result += "\nextern \"C\" __declspec(dllexport) struct _class_t "; - Result += VarName; Result += CDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__DATA,__objc_data\"))) = {\n"; - Result += "\t"; - if (metaclass) { - if (!rootClass) { - Result += "0, // &"; Result += VarName; - Result += RootClass->getNameAsString(); - Result += ",\n\t"; - Result += "0, // &"; Result += VarName; - Result += CDecl->getSuperClass()->getNameAsString(); - Result += ",\n\t"; - } - else { - Result += "0, // &"; Result += VarName; - Result += CDecl->getNameAsString(); - Result += ",\n\t"; - Result += "0, // &OBJC_CLASS_$_"; Result += CDecl->getNameAsString(); - Result += ",\n\t"; - } - } - else { - Result += "0, // &OBJC_METACLASS_$_"; - Result += CDecl->getNameAsString(); - Result += ",\n\t"; - if (!rootClass) { - Result += "0, // &"; Result += VarName; - Result += CDecl->getSuperClass()->getNameAsString(); - Result += ",\n\t"; - } - else - Result += "0,\n\t"; - } - Result += "0, // (void *)&_objc_empty_cache,\n\t"; - Result += "0, // unused, was (void *)&_objc_empty_vtable,\n\t"; - if (metaclass) - Result += "&_OBJC_METACLASS_RO_$_"; - else - Result += "&_OBJC_CLASS_RO_$_"; - Result += CDecl->getNameAsString(); - Result += ",\n};\n"; - - // Add static function to initialize some of the meta-data fields. - // avoid doing it twice. - if (metaclass) - return; - - const ObjCInterfaceDecl *SuperClass = - rootClass ? CDecl : CDecl->getSuperClass(); - - Result += "static void OBJC_CLASS_SETUP_$_"; - Result += CDecl->getNameAsString(); - Result += "(void ) {\n"; - Result += "\tOBJC_METACLASS_$_"; Result += CDecl->getNameAsString(); - Result += ".isa = "; Result += "&OBJC_METACLASS_$_"; - Result += RootClass->getNameAsString(); Result += ";\n"; - - Result += "\tOBJC_METACLASS_$_"; Result += CDecl->getNameAsString(); - Result += ".superclass = "; - if (rootClass) - Result += "&OBJC_CLASS_$_"; - else - Result += "&OBJC_METACLASS_$_"; - - Result += SuperClass->getNameAsString(); Result += ";\n"; - - Result += "\tOBJC_METACLASS_$_"; Result += CDecl->getNameAsString(); - Result += ".cache = "; Result += "&_objc_empty_cache"; Result += ";\n"; - - Result += "\tOBJC_CLASS_$_"; Result += CDecl->getNameAsString(); - Result += ".isa = "; Result += "&OBJC_METACLASS_$_"; - Result += CDecl->getNameAsString(); Result += ";\n"; - - if (!rootClass) { - Result += "\tOBJC_CLASS_$_"; Result += CDecl->getNameAsString(); - Result += ".superclass = "; Result += "&OBJC_CLASS_$_"; - Result += SuperClass->getNameAsString(); Result += ";\n"; - } - - Result += "\tOBJC_CLASS_$_"; Result += CDecl->getNameAsString(); - Result += ".cache = "; Result += "&_objc_empty_cache"; Result += ";\n"; - Result += "}\n"; -} - -static void Write_category_t(RewriteModernObjC &RewriteObj, ASTContext *Context, - std::string &Result, - ObjCCategoryDecl *CatDecl, - ObjCInterfaceDecl *ClassDecl, - ArrayRef<ObjCMethodDecl *> InstanceMethods, - ArrayRef<ObjCMethodDecl *> ClassMethods, - ArrayRef<ObjCProtocolDecl *> RefedProtocols, - ArrayRef<ObjCPropertyDecl *> ClassProperties) { - StringRef CatName = CatDecl->getName(); - StringRef ClassName = ClassDecl->getName(); - // must declare an extern class object in case this class is not implemented - // in this TU. - Result += "\n"; - Result += "extern \"C\" "; - if (ClassDecl->getImplementation()) - Result += "__declspec(dllexport) "; - else - Result += "__declspec(dllimport) "; - - Result += "struct _class_t "; - Result += "OBJC_CLASS_$_"; Result += ClassName; - Result += ";\n"; - - Result += "\nstatic struct _category_t "; - Result += "_OBJC_$_CATEGORY_"; - Result += ClassName; Result += "_$_"; Result += CatName; - Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = \n"; - Result += "{\n"; - Result += "\t\""; Result += ClassName; Result += "\",\n"; - Result += "\t0, // &"; Result += "OBJC_CLASS_$_"; Result += ClassName; - Result += ",\n"; - if (InstanceMethods.size() > 0) { - Result += "\t(const struct _method_list_t *)&"; - Result += "_OBJC_$_CATEGORY_INSTANCE_METHODS_"; - Result += ClassName; Result += "_$_"; Result += CatName; - Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (ClassMethods.size() > 0) { - Result += "\t(const struct _method_list_t *)&"; - Result += "_OBJC_$_CATEGORY_CLASS_METHODS_"; - Result += ClassName; Result += "_$_"; Result += CatName; - Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (RefedProtocols.size() > 0) { - Result += "\t(const struct _protocol_list_t *)&"; - Result += "_OBJC_CATEGORY_PROTOCOLS_$_"; - Result += ClassName; Result += "_$_"; Result += CatName; - Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (ClassProperties.size() > 0) { - Result += "\t(const struct _prop_list_t *)&"; Result += "_OBJC_$_PROP_LIST_"; - Result += ClassName; Result += "_$_"; Result += CatName; - Result += ",\n"; - } - else - Result += "\t0,\n"; - - Result += "};\n"; - - // Add static function to initialize the class pointer in the category structure. - Result += "static void OBJC_CATEGORY_SETUP_$_"; - Result += ClassDecl->getNameAsString(); - Result += "_$_"; - Result += CatName; - Result += "(void ) {\n"; - Result += "\t_OBJC_$_CATEGORY_"; - Result += ClassDecl->getNameAsString(); - Result += "_$_"; - Result += CatName; - Result += ".cls = "; Result += "&OBJC_CLASS_$_"; Result += ClassName; - Result += ";\n}\n"; -} - -static void Write__extendedMethodTypes_initializer(RewriteModernObjC &RewriteObj, - ASTContext *Context, std::string &Result, - ArrayRef<ObjCMethodDecl *> Methods, - StringRef VarName, - StringRef ProtocolName) { - if (Methods.size() == 0) - return; - - Result += "\nstatic const char *"; - Result += VarName; Result += ProtocolName; - Result += " [] __attribute__ ((used, section (\"__DATA,__objc_const\"))) = \n"; - Result += "{\n"; - for (unsigned i = 0, e = Methods.size(); i < e; i++) { - ObjCMethodDecl *MD = Methods[i]; - std::string MethodTypeString, QuoteMethodTypeString; - Context->getObjCEncodingForMethodDecl(MD, MethodTypeString, true); - RewriteObj.QuoteDoublequotes(MethodTypeString, QuoteMethodTypeString); - Result += "\t\""; Result += QuoteMethodTypeString; Result += "\""; - if (i == e-1) - Result += "\n};\n"; - else { - Result += ",\n"; - } - } -} - -static void Write_IvarOffsetVar(RewriteModernObjC &RewriteObj, - ASTContext *Context, - std::string &Result, - ArrayRef<ObjCIvarDecl *> Ivars, - ObjCInterfaceDecl *CDecl) { - // FIXME. visibilty of offset symbols may have to be set; for Darwin - // this is what happens: - /** - if (Ivar->getAccessControl() == ObjCIvarDecl::Private || - Ivar->getAccessControl() == ObjCIvarDecl::Package || - Class->getVisibility() == HiddenVisibility) - Visibility shoud be: HiddenVisibility; - else - Visibility shoud be: DefaultVisibility; - */ - - Result += "\n"; - for (unsigned i =0, e = Ivars.size(); i < e; i++) { - ObjCIvarDecl *IvarDecl = Ivars[i]; - if (Context->getLangOpts().MicrosoftExt) - Result += "__declspec(allocate(\".objc_ivar$B\")) "; - - if (!Context->getLangOpts().MicrosoftExt || - IvarDecl->getAccessControl() == ObjCIvarDecl::Private || - IvarDecl->getAccessControl() == ObjCIvarDecl::Package) - Result += "extern \"C\" unsigned long int "; - else - Result += "extern \"C\" __declspec(dllexport) unsigned long int "; - if (Ivars[i]->isBitField()) - RewriteObj.ObjCIvarBitfieldGroupOffset(IvarDecl, Result); - else - WriteInternalIvarName(CDecl, IvarDecl, Result); - Result += " __attribute__ ((used, section (\"__DATA,__objc_ivar\")))"; - Result += " = "; - RewriteObj.RewriteIvarOffsetComputation(IvarDecl, Result); - Result += ";\n"; - if (Ivars[i]->isBitField()) { - // skip over rest of the ivar bitfields. - SKIP_BITFIELDS(i , e, Ivars); - } - } -} - -static void Write__ivar_list_t_initializer(RewriteModernObjC &RewriteObj, - ASTContext *Context, std::string &Result, - ArrayRef<ObjCIvarDecl *> OriginalIvars, - StringRef VarName, - ObjCInterfaceDecl *CDecl) { - if (OriginalIvars.size() > 0) { - Write_IvarOffsetVar(RewriteObj, Context, Result, OriginalIvars, CDecl); - SmallVector<ObjCIvarDecl *, 8> Ivars; - // strip off all but the first ivar bitfield from each group of ivars. - // Such ivars in the ivar list table will be replaced by their grouping struct - // 'ivar'. - for (unsigned i = 0, e = OriginalIvars.size(); i < e; i++) { - if (OriginalIvars[i]->isBitField()) { - Ivars.push_back(OriginalIvars[i]); - // skip over rest of the ivar bitfields. - SKIP_BITFIELDS(i , e, OriginalIvars); - } - else - Ivars.push_back(OriginalIvars[i]); - } - - Result += "\nstatic "; - Write__ivar_list_t_TypeDecl(Result, Ivars.size()); - Result += " "; Result += VarName; - Result += CDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n"; - Result += "\t"; Result += "sizeof(_ivar_t)"; Result += ",\n"; - Result += "\t"; Result += utostr(Ivars.size()); Result += ",\n"; - for (unsigned i =0, e = Ivars.size(); i < e; i++) { - ObjCIvarDecl *IvarDecl = Ivars[i]; - if (i == 0) - Result += "\t{{"; - else - Result += "\t {"; - Result += "(unsigned long int *)&"; - if (Ivars[i]->isBitField()) - RewriteObj.ObjCIvarBitfieldGroupOffset(IvarDecl, Result); - else - WriteInternalIvarName(CDecl, IvarDecl, Result); - Result += ", "; - - Result += "\""; - if (Ivars[i]->isBitField()) - RewriteObj.ObjCIvarBitfieldGroupDecl(Ivars[i], Result); - else - Result += IvarDecl->getName(); - Result += "\", "; - - QualType IVQT = IvarDecl->getType(); - if (IvarDecl->isBitField()) - IVQT = RewriteObj.GetGroupRecordTypeForObjCIvarBitfield(IvarDecl); - - std::string IvarTypeString, QuoteIvarTypeString; - Context->getObjCEncodingForType(IVQT, IvarTypeString, - IvarDecl); - RewriteObj.QuoteDoublequotes(IvarTypeString, QuoteIvarTypeString); - Result += "\""; Result += QuoteIvarTypeString; Result += "\", "; - - // FIXME. this alignment represents the host alignment and need be changed to - // represent the target alignment. - unsigned Align = Context->getTypeAlign(IVQT)/8; - Align = llvm::Log2_32(Align); - Result += llvm::utostr(Align); Result += ", "; - CharUnits Size = Context->getTypeSizeInChars(IVQT); - Result += llvm::utostr(Size.getQuantity()); - if (i == e-1) - Result += "}}\n"; - else - Result += "},\n"; - } - Result += "};\n"; - } -} - -/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data. -void RewriteModernObjC::RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, - std::string &Result) { - - // Do not synthesize the protocol more than once. - if (ObjCSynthesizedProtocols.count(PDecl->getCanonicalDecl())) - return; - WriteModernMetadataDeclarations(Context, Result); - - if (ObjCProtocolDecl *Def = PDecl->getDefinition()) - PDecl = Def; - // Must write out all protocol definitions in current qualifier list, - // and in their nested qualifiers before writing out current definition. - for (auto *I : PDecl->protocols()) - RewriteObjCProtocolMetaData(I, Result); - - // Construct method lists. - std::vector<ObjCMethodDecl *> InstanceMethods, ClassMethods; - std::vector<ObjCMethodDecl *> OptInstanceMethods, OptClassMethods; - for (auto *MD : PDecl->instance_methods()) { - if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { - OptInstanceMethods.push_back(MD); - } else { - InstanceMethods.push_back(MD); - } - } - - for (auto *MD : PDecl->class_methods()) { - if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { - OptClassMethods.push_back(MD); - } else { - ClassMethods.push_back(MD); - } - } - std::vector<ObjCMethodDecl *> AllMethods; - for (unsigned i = 0, e = InstanceMethods.size(); i < e; i++) - AllMethods.push_back(InstanceMethods[i]); - for (unsigned i = 0, e = ClassMethods.size(); i < e; i++) - AllMethods.push_back(ClassMethods[i]); - for (unsigned i = 0, e = OptInstanceMethods.size(); i < e; i++) - AllMethods.push_back(OptInstanceMethods[i]); - for (unsigned i = 0, e = OptClassMethods.size(); i < e; i++) - AllMethods.push_back(OptClassMethods[i]); - - Write__extendedMethodTypes_initializer(*this, Context, Result, - AllMethods, - "_OBJC_PROTOCOL_METHOD_TYPES_", - PDecl->getNameAsString()); - // Protocol's super protocol list - SmallVector<ObjCProtocolDecl *, 8> SuperProtocols(PDecl->protocols()); - Write_protocol_list_initializer(Context, Result, SuperProtocols, - "_OBJC_PROTOCOL_REFS_", - PDecl->getNameAsString()); - - Write_method_list_t_initializer(*this, Context, Result, InstanceMethods, - "_OBJC_PROTOCOL_INSTANCE_METHODS_", - PDecl->getNameAsString(), false); - - Write_method_list_t_initializer(*this, Context, Result, ClassMethods, - "_OBJC_PROTOCOL_CLASS_METHODS_", - PDecl->getNameAsString(), false); - - Write_method_list_t_initializer(*this, Context, Result, OptInstanceMethods, - "_OBJC_PROTOCOL_OPT_INSTANCE_METHODS_", - PDecl->getNameAsString(), false); - - Write_method_list_t_initializer(*this, Context, Result, OptClassMethods, - "_OBJC_PROTOCOL_OPT_CLASS_METHODS_", - PDecl->getNameAsString(), false); - - // Protocol's property metadata. - SmallVector<ObjCPropertyDecl *, 8> ProtocolProperties(PDecl->properties()); - Write_prop_list_t_initializer(*this, Context, Result, ProtocolProperties, - /* Container */nullptr, - "_OBJC_PROTOCOL_PROPERTIES_", - PDecl->getNameAsString()); - - // Writer out root metadata for current protocol: struct _protocol_t - Result += "\n"; - if (LangOpts.MicrosoftExt) - Result += "static "; - Result += "struct _protocol_t _OBJC_PROTOCOL_"; - Result += PDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__DATA,__datacoal_nt,coalesced\"))) = {\n"; - Result += "\t0,\n"; // id is; is null - Result += "\t\""; Result += PDecl->getNameAsString(); Result += "\",\n"; - if (SuperProtocols.size() > 0) { - Result += "\t(const struct _protocol_list_t *)&"; Result += "_OBJC_PROTOCOL_REFS_"; - Result += PDecl->getNameAsString(); Result += ",\n"; - } - else - Result += "\t0,\n"; - if (InstanceMethods.size() > 0) { - Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_INSTANCE_METHODS_"; - Result += PDecl->getNameAsString(); Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (ClassMethods.size() > 0) { - Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_CLASS_METHODS_"; - Result += PDecl->getNameAsString(); Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (OptInstanceMethods.size() > 0) { - Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_OPT_INSTANCE_METHODS_"; - Result += PDecl->getNameAsString(); Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (OptClassMethods.size() > 0) { - Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_OPT_CLASS_METHODS_"; - Result += PDecl->getNameAsString(); Result += ",\n"; - } - else - Result += "\t0,\n"; - - if (ProtocolProperties.size() > 0) { - Result += "\t(const struct _prop_list_t *)&_OBJC_PROTOCOL_PROPERTIES_"; - Result += PDecl->getNameAsString(); Result += ",\n"; - } - else - Result += "\t0,\n"; - - Result += "\t"; Result += "sizeof(_protocol_t)"; Result += ",\n"; - Result += "\t0,\n"; - - if (AllMethods.size() > 0) { - Result += "\t(const char **)&"; Result += "_OBJC_PROTOCOL_METHOD_TYPES_"; - Result += PDecl->getNameAsString(); - Result += "\n};\n"; - } - else - Result += "\t0\n};\n"; - - if (LangOpts.MicrosoftExt) - Result += "static "; - Result += "struct _protocol_t *"; - Result += "_OBJC_LABEL_PROTOCOL_$_"; Result += PDecl->getNameAsString(); - Result += " = &_OBJC_PROTOCOL_"; Result += PDecl->getNameAsString(); - Result += ";\n"; - - // Mark this protocol as having been generated. - if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl())) - llvm_unreachable("protocol already synthesized"); - -} - -void RewriteModernObjC::RewriteObjCProtocolListMetaData( - const ObjCList<ObjCProtocolDecl> &Protocols, - StringRef prefix, StringRef ClassName, - std::string &Result) { - if (Protocols.empty()) return; - - for (unsigned i = 0; i != Protocols.size(); i++) - RewriteObjCProtocolMetaData(Protocols[i], Result); - - // Output the top lovel protocol meta-data for the class. - /* struct _objc_protocol_list { - struct _objc_protocol_list *next; - int protocol_count; - struct _objc_protocol *class_protocols[]; - } - */ - Result += "\n"; - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".cat_cls_meth$B\")) "; - Result += "static struct {\n"; - Result += "\tstruct _objc_protocol_list *next;\n"; - Result += "\tint protocol_count;\n"; - Result += "\tstruct _objc_protocol *class_protocols["; - Result += utostr(Protocols.size()); - Result += "];\n} _OBJC_"; - Result += prefix; - Result += "_PROTOCOLS_"; - Result += ClassName; - Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= " - "{\n\t0, "; - Result += utostr(Protocols.size()); - Result += "\n"; - - Result += "\t,{&_OBJC_PROTOCOL_"; - Result += Protocols[0]->getNameAsString(); - Result += " \n"; - - for (unsigned i = 1; i != Protocols.size(); i++) { - Result += "\t ,&_OBJC_PROTOCOL_"; - Result += Protocols[i]->getNameAsString(); - Result += "\n"; - } - Result += "\t }\n};\n"; -} - -/// hasObjCExceptionAttribute - Return true if this class or any super -/// class has the __objc_exception__ attribute. -/// FIXME. Move this to ASTContext.cpp as it is also used for IRGen. -static bool hasObjCExceptionAttribute(ASTContext &Context, - const ObjCInterfaceDecl *OID) { - if (OID->hasAttr<ObjCExceptionAttr>()) - return true; - if (const ObjCInterfaceDecl *Super = OID->getSuperClass()) - return hasObjCExceptionAttribute(Context, Super); - return false; -} - -void RewriteModernObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, - std::string &Result) { - ObjCInterfaceDecl *CDecl = IDecl->getClassInterface(); - - // Explicitly declared @interface's are already synthesized. - if (CDecl->isImplicitInterfaceDecl()) - assert(false && - "Legacy implicit interface rewriting not supported in moder abi"); - - WriteModernMetadataDeclarations(Context, Result); - SmallVector<ObjCIvarDecl *, 8> IVars; - - for (ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin(); - IVD; IVD = IVD->getNextIvar()) { - // Ignore unnamed bit-fields. - if (!IVD->getDeclName()) - continue; - IVars.push_back(IVD); - } - - Write__ivar_list_t_initializer(*this, Context, Result, IVars, - "_OBJC_$_INSTANCE_VARIABLES_", - CDecl); - - // Build _objc_method_list for class's instance methods if needed - SmallVector<ObjCMethodDecl *, 32> InstanceMethods(IDecl->instance_methods()); - - // If any of our property implementations have associated getters or - // setters, produce metadata for them as well. - for (const auto *Prop : IDecl->property_impls()) { - if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - continue; - if (!Prop->getPropertyIvarDecl()) - continue; - ObjCPropertyDecl *PD = Prop->getPropertyDecl(); - if (!PD) - continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) - if (mustSynthesizeSetterGetterMethod(IDecl, PD, true /*getter*/)) - InstanceMethods.push_back(Getter); - if (PD->isReadOnly()) - continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) - if (mustSynthesizeSetterGetterMethod(IDecl, PD, false /*setter*/)) - InstanceMethods.push_back(Setter); - } - - Write_method_list_t_initializer(*this, Context, Result, InstanceMethods, - "_OBJC_$_INSTANCE_METHODS_", - IDecl->getNameAsString(), true); - - SmallVector<ObjCMethodDecl *, 32> ClassMethods(IDecl->class_methods()); - - Write_method_list_t_initializer(*this, Context, Result, ClassMethods, - "_OBJC_$_CLASS_METHODS_", - IDecl->getNameAsString(), true); - - // Protocols referenced in class declaration? - // Protocol's super protocol list - std::vector<ObjCProtocolDecl *> RefedProtocols; - const ObjCList<ObjCProtocolDecl> &Protocols = CDecl->getReferencedProtocols(); - for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), - E = Protocols.end(); - I != E; ++I) { - RefedProtocols.push_back(*I); - // Must write out all protocol definitions in current qualifier list, - // and in their nested qualifiers before writing out current definition. - RewriteObjCProtocolMetaData(*I, Result); - } - - Write_protocol_list_initializer(Context, Result, - RefedProtocols, - "_OBJC_CLASS_PROTOCOLS_$_", - IDecl->getNameAsString()); - - // Protocol's property metadata. - SmallVector<ObjCPropertyDecl *, 8> ClassProperties(CDecl->properties()); - Write_prop_list_t_initializer(*this, Context, Result, ClassProperties, - /* Container */IDecl, - "_OBJC_$_PROP_LIST_", - CDecl->getNameAsString()); - - - // Data for initializing _class_ro_t metaclass meta-data - uint32_t flags = CLS_META; - std::string InstanceSize; - std::string InstanceStart; - - - bool classIsHidden = CDecl->getVisibility() == HiddenVisibility; - if (classIsHidden) - flags |= OBJC2_CLS_HIDDEN; - - if (!CDecl->getSuperClass()) - // class is root - flags |= CLS_ROOT; - InstanceSize = "sizeof(struct _class_t)"; - InstanceStart = InstanceSize; - Write__class_ro_t_initializer(Context, Result, flags, - InstanceStart, InstanceSize, - ClassMethods, - nullptr, - nullptr, - nullptr, - "_OBJC_METACLASS_RO_$_", - CDecl->getNameAsString()); - - // Data for initializing _class_ro_t meta-data - flags = CLS; - if (classIsHidden) - flags |= OBJC2_CLS_HIDDEN; - - if (hasObjCExceptionAttribute(*Context, CDecl)) - flags |= CLS_EXCEPTION; - - if (!CDecl->getSuperClass()) - // class is root - flags |= CLS_ROOT; - - InstanceSize.clear(); - InstanceStart.clear(); - if (!ObjCSynthesizedStructs.count(CDecl)) { - InstanceSize = "0"; - InstanceStart = "0"; - } - else { - InstanceSize = "sizeof(struct "; - InstanceSize += CDecl->getNameAsString(); - InstanceSize += "_IMPL)"; - - ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin(); - if (IVD) { - RewriteIvarOffsetComputation(IVD, InstanceStart); - } - else - InstanceStart = InstanceSize; - } - Write__class_ro_t_initializer(Context, Result, flags, - InstanceStart, InstanceSize, - InstanceMethods, - RefedProtocols, - IVars, - ClassProperties, - "_OBJC_CLASS_RO_$_", - CDecl->getNameAsString()); - - Write_class_t(Context, Result, - "OBJC_METACLASS_$_", - CDecl, /*metaclass*/true); - - Write_class_t(Context, Result, - "OBJC_CLASS_$_", - CDecl, /*metaclass*/false); - - if (ImplementationIsNonLazy(IDecl)) - DefinedNonLazyClasses.push_back(CDecl); - -} - -void RewriteModernObjC::RewriteClassSetupInitHook(std::string &Result) { - int ClsDefCount = ClassImplementation.size(); - if (!ClsDefCount) - return; - Result += "#pragma section(\".objc_inithooks$B\", long, read, write)\n"; - Result += "__declspec(allocate(\".objc_inithooks$B\")) "; - Result += "static void *OBJC_CLASS_SETUP[] = {\n"; - for (int i = 0; i < ClsDefCount; i++) { - ObjCImplementationDecl *IDecl = ClassImplementation[i]; - ObjCInterfaceDecl *CDecl = IDecl->getClassInterface(); - Result += "\t(void *)&OBJC_CLASS_SETUP_$_"; - Result += CDecl->getName(); Result += ",\n"; - } - Result += "};\n"; -} - -void RewriteModernObjC::RewriteMetaDataIntoBuffer(std::string &Result) { - int ClsDefCount = ClassImplementation.size(); - int CatDefCount = CategoryImplementation.size(); - - // For each implemented class, write out all its meta data. - for (int i = 0; i < ClsDefCount; i++) - RewriteObjCClassMetaData(ClassImplementation[i], Result); - - RewriteClassSetupInitHook(Result); - - // For each implemented category, write out all its meta data. - for (int i = 0; i < CatDefCount; i++) - RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result); - - RewriteCategorySetupInitHook(Result); - - if (ClsDefCount > 0) { - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".objc_classlist$B\")) "; - Result += "static struct _class_t *L_OBJC_LABEL_CLASS_$ ["; - Result += llvm::utostr(ClsDefCount); Result += "]"; - Result += - " __attribute__((used, section (\"__DATA, __objc_classlist," - "regular,no_dead_strip\")))= {\n"; - for (int i = 0; i < ClsDefCount; i++) { - Result += "\t&OBJC_CLASS_$_"; - Result += ClassImplementation[i]->getNameAsString(); - Result += ",\n"; - } - Result += "};\n"; - - if (!DefinedNonLazyClasses.empty()) { - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".objc_nlclslist$B\")) \n"; - Result += "static struct _class_t *_OBJC_LABEL_NONLAZY_CLASS_$[] = {\n\t"; - for (unsigned i = 0, e = DefinedNonLazyClasses.size(); i < e; i++) { - Result += "\t&OBJC_CLASS_$_"; Result += DefinedNonLazyClasses[i]->getNameAsString(); - Result += ",\n"; - } - Result += "};\n"; - } - } - - if (CatDefCount > 0) { - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".objc_catlist$B\")) "; - Result += "static struct _category_t *L_OBJC_LABEL_CATEGORY_$ ["; - Result += llvm::utostr(CatDefCount); Result += "]"; - Result += - " __attribute__((used, section (\"__DATA, __objc_catlist," - "regular,no_dead_strip\")))= {\n"; - for (int i = 0; i < CatDefCount; i++) { - Result += "\t&_OBJC_$_CATEGORY_"; - Result += - CategoryImplementation[i]->getClassInterface()->getNameAsString(); - Result += "_$_"; - Result += CategoryImplementation[i]->getNameAsString(); - Result += ",\n"; - } - Result += "};\n"; - } - - if (!DefinedNonLazyCategories.empty()) { - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".objc_nlcatlist$B\")) \n"; - Result += "static struct _category_t *_OBJC_LABEL_NONLAZY_CATEGORY_$[] = {\n\t"; - for (unsigned i = 0, e = DefinedNonLazyCategories.size(); i < e; i++) { - Result += "\t&_OBJC_$_CATEGORY_"; - Result += - DefinedNonLazyCategories[i]->getClassInterface()->getNameAsString(); - Result += "_$_"; - Result += DefinedNonLazyCategories[i]->getNameAsString(); - Result += ",\n"; - } - Result += "};\n"; - } -} - -void RewriteModernObjC::WriteImageInfo(std::string &Result) { - if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".objc_imageinfo$B\")) \n"; - - Result += "static struct IMAGE_INFO { unsigned version; unsigned flag; } "; - // version 0, ObjCABI is 2 - Result += "_OBJC_IMAGE_INFO = { 0, 2 };\n"; -} - -/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category -/// implementation. -void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl, - std::string &Result) { - WriteModernMetadataDeclarations(Context, Result); - ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface(); - // Find category declaration for this implementation. - ObjCCategoryDecl *CDecl - = ClassDecl->FindCategoryDeclaration(IDecl->getIdentifier()); - - std::string FullCategoryName = ClassDecl->getNameAsString(); - FullCategoryName += "_$_"; - FullCategoryName += CDecl->getNameAsString(); - - // Build _objc_method_list for class's instance methods if needed - SmallVector<ObjCMethodDecl *, 32> InstanceMethods(IDecl->instance_methods()); - - // If any of our property implementations have associated getters or - // setters, produce metadata for them as well. - for (const auto *Prop : IDecl->property_impls()) { - if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - continue; - if (!Prop->getPropertyIvarDecl()) - continue; - ObjCPropertyDecl *PD = Prop->getPropertyDecl(); - if (!PD) - continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) - InstanceMethods.push_back(Getter); - if (PD->isReadOnly()) - continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) - InstanceMethods.push_back(Setter); - } - - Write_method_list_t_initializer(*this, Context, Result, InstanceMethods, - "_OBJC_$_CATEGORY_INSTANCE_METHODS_", - FullCategoryName, true); - - SmallVector<ObjCMethodDecl *, 32> ClassMethods(IDecl->class_methods()); - - Write_method_list_t_initializer(*this, Context, Result, ClassMethods, - "_OBJC_$_CATEGORY_CLASS_METHODS_", - FullCategoryName, true); - - // Protocols referenced in class declaration? - // Protocol's super protocol list - SmallVector<ObjCProtocolDecl *, 8> RefedProtocols(CDecl->protocols()); - for (auto *I : CDecl->protocols()) - // Must write out all protocol definitions in current qualifier list, - // and in their nested qualifiers before writing out current definition. - RewriteObjCProtocolMetaData(I, Result); - - Write_protocol_list_initializer(Context, Result, - RefedProtocols, - "_OBJC_CATEGORY_PROTOCOLS_$_", - FullCategoryName); - - // Protocol's property metadata. - SmallVector<ObjCPropertyDecl *, 8> ClassProperties(CDecl->properties()); - Write_prop_list_t_initializer(*this, Context, Result, ClassProperties, - /* Container */IDecl, - "_OBJC_$_PROP_LIST_", - FullCategoryName); - - Write_category_t(*this, Context, Result, - CDecl, - ClassDecl, - InstanceMethods, - ClassMethods, - RefedProtocols, - ClassProperties); - - // Determine if this category is also "non-lazy". - if (ImplementationIsNonLazy(IDecl)) - DefinedNonLazyCategories.push_back(CDecl); - -} - -void RewriteModernObjC::RewriteCategorySetupInitHook(std::string &Result) { - int CatDefCount = CategoryImplementation.size(); - if (!CatDefCount) - return; - Result += "#pragma section(\".objc_inithooks$B\", long, read, write)\n"; - Result += "__declspec(allocate(\".objc_inithooks$B\")) "; - Result += "static void *OBJC_CATEGORY_SETUP[] = {\n"; - for (int i = 0; i < CatDefCount; i++) { - ObjCCategoryImplDecl *IDecl = CategoryImplementation[i]; - ObjCCategoryDecl *CatDecl= IDecl->getCategoryDecl(); - ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface(); - Result += "\t(void *)&OBJC_CATEGORY_SETUP_$_"; - Result += ClassDecl->getName(); - Result += "_$_"; - Result += CatDecl->getName(); - Result += ",\n"; - } - Result += "};\n"; -} - -// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or -/// class methods. -template<typename MethodIterator> -void RewriteModernObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin, - MethodIterator MethodEnd, - bool IsInstanceMethod, - StringRef prefix, - StringRef ClassName, - std::string &Result) { - if (MethodBegin == MethodEnd) return; - - if (!objc_impl_method) { - /* struct _objc_method { - SEL _cmd; - char *method_types; - void *_imp; - } - */ - Result += "\nstruct _objc_method {\n"; - Result += "\tSEL _cmd;\n"; - Result += "\tchar *method_types;\n"; - Result += "\tvoid *_imp;\n"; - Result += "};\n"; - - objc_impl_method = true; - } - - // Build _objc_method_list for class's methods if needed - - /* struct { - struct _objc_method_list *next_method; - int method_count; - struct _objc_method method_list[]; - } - */ - unsigned NumMethods = std::distance(MethodBegin, MethodEnd); - Result += "\n"; - if (LangOpts.MicrosoftExt) { - if (IsInstanceMethod) - Result += "__declspec(allocate(\".inst_meth$B\")) "; - else - Result += "__declspec(allocate(\".cls_meth$B\")) "; - } - Result += "static struct {\n"; - Result += "\tstruct _objc_method_list *next_method;\n"; - Result += "\tint method_count;\n"; - Result += "\tstruct _objc_method method_list["; - Result += utostr(NumMethods); - Result += "];\n} _OBJC_"; - Result += prefix; - Result += IsInstanceMethod ? "INSTANCE" : "CLASS"; - Result += "_METHODS_"; - Result += ClassName; - Result += " __attribute__ ((used, section (\"__OBJC, __"; - Result += IsInstanceMethod ? "inst" : "cls"; - Result += "_meth\")))= "; - Result += "{\n\t0, " + utostr(NumMethods) + "\n"; - - Result += "\t,{{(SEL)\""; - Result += (*MethodBegin)->getSelector().getAsString().c_str(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\", (void *)"; - Result += MethodInternalNames[*MethodBegin]; - Result += "}\n"; - for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) { - Result += "\t ,{(SEL)\""; - Result += (*MethodBegin)->getSelector().getAsString().c_str(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\", (void *)"; - Result += MethodInternalNames[*MethodBegin]; - Result += "}\n"; - } - Result += "\t }\n};\n"; -} - -Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { - SourceRange OldRange = IV->getSourceRange(); - Expr *BaseExpr = IV->getBase(); - - // Rewrite the base, but without actually doing replaces. - { - DisableReplaceStmtScope S(*this); - BaseExpr = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(BaseExpr)); - IV->setBase(BaseExpr); - } - - ObjCIvarDecl *D = IV->getDecl(); - - Expr *Replacement = IV; - - if (BaseExpr->getType()->isObjCObjectPointerType()) { - const ObjCInterfaceType *iFaceDecl = - dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType()); - assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null"); - // lookup which class implements the instance variable. - ObjCInterfaceDecl *clsDeclared = nullptr; - iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), - clsDeclared); - assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class"); - - // Build name of symbol holding ivar offset. - std::string IvarOffsetName; - if (D->isBitField()) - ObjCIvarBitfieldGroupOffset(D, IvarOffsetName); - else - WriteInternalIvarName(clsDeclared, D, IvarOffsetName); - - ReferencedIvars[clsDeclared].insert(D); - - // cast offset to "char *". - CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->CharTy), - CK_BitCast, - BaseExpr); - VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), &Context->Idents.get(IvarOffsetName), - Context->UnsignedLongTy, nullptr, - SC_Extern); - DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, - Context->UnsignedLongTy, VK_LValue, - SourceLocation()); - BinaryOperator *addExpr = - new (Context) BinaryOperator(castExpr, DRE, BO_Add, - Context->getPointerType(Context->CharTy), - VK_RValue, OK_Ordinary, SourceLocation(), false); - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), - SourceLocation(), - addExpr); - QualType IvarT = D->getType(); - if (D->isBitField()) - IvarT = GetGroupRecordTypeForObjCIvarBitfield(D); - - if (!isa<TypedefType>(IvarT) && IvarT->isRecordType()) { - RecordDecl *RD = IvarT->getAs<RecordType>()->getDecl(); - RD = RD->getDefinition(); - if (RD && !RD->getDeclName().getAsIdentifierInfo()) { - // decltype(((Foo_IMPL*)0)->bar) * - ObjCContainerDecl *CDecl = - dyn_cast<ObjCContainerDecl>(D->getDeclContext()); - // ivar in class extensions requires special treatment. - if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) - CDecl = CatDecl->getClassInterface(); - std::string RecName = CDecl->getName(); - RecName += "_IMPL"; - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get(RecName.c_str())); - QualType PtrStructIMPL = Context->getPointerType(Context->getTagDeclType(RD)); - unsigned UnsignedIntSize = - static_cast<unsigned>(Context->getTypeSize(Context->UnsignedIntTy)); - Expr *Zero = IntegerLiteral::Create(*Context, - llvm::APInt(UnsignedIntSize, 0), - Context->UnsignedIntTy, SourceLocation()); - Zero = NoTypeInfoCStyleCastExpr(Context, PtrStructIMPL, CK_BitCast, Zero); - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - Zero); - FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), - SourceLocation(), - &Context->Idents.get(D->getNameAsString()), - IvarT, nullptr, - /*BitWidth=*/nullptr, - /*Mutable=*/true, ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), - FD->getType(), VK_LValue, - OK_Ordinary); - IvarT = Context->getDecltypeType(ME, ME->getType()); - } - } - convertObjCTypeToCStyleType(IvarT); - QualType castT = Context->getPointerType(IvarT); - - castExpr = NoTypeInfoCStyleCastExpr(Context, - castT, - CK_BitCast, - PE); - - - Expr *Exp = new (Context) UnaryOperator(castExpr, UO_Deref, IvarT, - VK_LValue, OK_Ordinary, - SourceLocation()); - PE = new (Context) ParenExpr(OldRange.getBegin(), - OldRange.getEnd(), - Exp); - - if (D->isBitField()) { - FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), - SourceLocation(), - &Context->Idents.get(D->getNameAsString()), - D->getType(), nullptr, - /*BitWidth=*/D->getBitWidth(), - /*Mutable=*/true, ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(PE, /*isArrow*/false, FD, SourceLocation(), - FD->getType(), VK_LValue, - OK_Ordinary); - Replacement = ME; - - } - else - Replacement = PE; - } - - ReplaceStmtWithRange(IV, Replacement, OldRange); - return Replacement; -} diff --git a/clang/lib/Rewrite/Frontend/RewriteObjC.cpp b/clang/lib/Rewrite/Frontend/RewriteObjC.cpp deleted file mode 100644 index dfeb11a9aa71..000000000000 --- a/clang/lib/Rewrite/Frontend/RewriteObjC.cpp +++ /dev/null @@ -1,5948 +0,0 @@ -//===--- RewriteObjC.cpp - Playground for the code rewriter ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Hacks and fun related to the code rewriter. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Frontend/ASTConsumers.h" -#include "clang/AST/AST.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/Attr.h" -#include "clang/AST/ParentMap.h" -#include "clang/Basic/CharInfo.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Lexer.h" -#include "clang/Rewrite/Core/Rewriter.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include <memory> - -using namespace clang; -using llvm::utostr; - -namespace { - class RewriteObjC : public ASTConsumer { - protected: - - enum { - BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), - block, ... */ - BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */ - BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the - __block variable */ - BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy - helpers */ - BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose - support routines */ - BLOCK_BYREF_CURRENT_MAX = 256 - }; - - enum { - BLOCK_NEEDS_FREE = (1 << 24), - BLOCK_HAS_COPY_DISPOSE = (1 << 25), - BLOCK_HAS_CXX_OBJ = (1 << 26), - BLOCK_IS_GC = (1 << 27), - BLOCK_IS_GLOBAL = (1 << 28), - BLOCK_HAS_DESCRIPTOR = (1 << 29) - }; - static const int OBJC_ABI_VERSION = 7; - - Rewriter Rewrite; - DiagnosticsEngine &Diags; - const LangOptions &LangOpts; - ASTContext *Context; - SourceManager *SM; - TranslationUnitDecl *TUDecl; - FileID MainFileID; - const char *MainFileStart, *MainFileEnd; - Stmt *CurrentBody; - ParentMap *PropParentMap; // created lazily. - std::string InFileName; - raw_ostream* OutFile; - std::string Preamble; - - TypeDecl *ProtocolTypeDecl; - VarDecl *GlobalVarDecl; - unsigned RewriteFailedDiag; - // ObjC string constant support. - unsigned NumObjCStringLiterals; - VarDecl *ConstantStringClassReference; - RecordDecl *NSStringRecord; - - // ObjC foreach break/continue generation support. - int BcLabelCount; - - unsigned TryFinallyContainsReturnDiag; - // Needed for super. - ObjCMethodDecl *CurMethodDef; - RecordDecl *SuperStructDecl; - RecordDecl *ConstantStringDecl; - - FunctionDecl *MsgSendFunctionDecl; - FunctionDecl *MsgSendSuperFunctionDecl; - FunctionDecl *MsgSendStretFunctionDecl; - FunctionDecl *MsgSendSuperStretFunctionDecl; - FunctionDecl *MsgSendFpretFunctionDecl; - FunctionDecl *GetClassFunctionDecl; - FunctionDecl *GetMetaClassFunctionDecl; - FunctionDecl *GetSuperClassFunctionDecl; - FunctionDecl *SelGetUidFunctionDecl; - FunctionDecl *CFStringFunctionDecl; - FunctionDecl *SuperConstructorFunctionDecl; - FunctionDecl *CurFunctionDef; - FunctionDecl *CurFunctionDeclToDeclareForBlock; - - /* Misc. containers needed for meta-data rewrite. */ - SmallVector<ObjCImplementationDecl *, 8> ClassImplementation; - SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation; - llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs; - llvm::SmallPtrSet<ObjCProtocolDecl*, 8> ObjCSynthesizedProtocols; - llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCForwardDecls; - llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames; - SmallVector<Stmt *, 32> Stmts; - SmallVector<int, 8> ObjCBcLabelNo; - // Remember all the @protocol(<expr>) expressions. - llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls; - - llvm::DenseSet<uint64_t> CopyDestroyCache; - - // Block expressions. - SmallVector<BlockExpr *, 32> Blocks; - SmallVector<int, 32> InnerDeclRefsCount; - SmallVector<DeclRefExpr *, 32> InnerDeclRefs; - - SmallVector<DeclRefExpr *, 32> BlockDeclRefs; - - // Block related declarations. - SmallVector<ValueDecl *, 8> BlockByCopyDecls; - llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet; - SmallVector<ValueDecl *, 8> BlockByRefDecls; - llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet; - llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo; - llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls; - llvm::SmallPtrSet<VarDecl *, 8> ImportedLocalExternalDecls; - - llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs; - - // This maps an original source AST to it's rewritten form. This allows - // us to avoid rewriting the same node twice (which is very uncommon). - // This is needed to support some of the exotic property rewriting. - llvm::DenseMap<Stmt *, Stmt *> ReplacedNodes; - - // Needed for header files being rewritten - bool IsHeader; - bool SilenceRewriteMacroWarning; - bool objc_impl_method; - - bool DisableReplaceStmt; - class DisableReplaceStmtScope { - RewriteObjC &R; - bool SavedValue; - - public: - DisableReplaceStmtScope(RewriteObjC &R) - : R(R), SavedValue(R.DisableReplaceStmt) { - R.DisableReplaceStmt = true; - } - ~DisableReplaceStmtScope() { - R.DisableReplaceStmt = SavedValue; - } - }; - void InitializeCommon(ASTContext &context); - - public: - - // Top Level Driver code. - bool HandleTopLevelDecl(DeclGroupRef D) override { - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { - if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*I)) { - if (!Class->isThisDeclarationADefinition()) { - RewriteForwardClassDecl(D); - break; - } - } - - if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*I)) { - if (!Proto->isThisDeclarationADefinition()) { - RewriteForwardProtocolDecl(D); - break; - } - } - - HandleTopLevelSingleDecl(*I); - } - return true; - } - void HandleTopLevelSingleDecl(Decl *D); - void HandleDeclInMainFile(Decl *D); - RewriteObjC(std::string inFile, raw_ostream *OS, - DiagnosticsEngine &D, const LangOptions &LOpts, - bool silenceMacroWarn); - - ~RewriteObjC() {} - - void HandleTranslationUnit(ASTContext &C) override; - - void ReplaceStmt(Stmt *Old, Stmt *New) { - Stmt *ReplacingStmt = ReplacedNodes[Old]; - - if (ReplacingStmt) - return; // We can't rewrite the same node twice. - - if (DisableReplaceStmt) - return; - - // If replacement succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceStmt(Old, New)) { - ReplacedNodes[Old] = New; - return; - } - if (SilenceRewriteMacroWarning) - return; - Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) - << Old->getSourceRange(); - } - - void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) { - assert(Old != nullptr && New != nullptr && "Expected non-null Stmt's"); - if (DisableReplaceStmt) - return; - - // Measure the old text. - int Size = Rewrite.getRangeSize(SrcRange); - if (Size == -1) { - Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) - << Old->getSourceRange(); - return; - } - // Get the new text. - std::string SStr; - llvm::raw_string_ostream S(SStr); - New->printPretty(S, nullptr, PrintingPolicy(LangOpts)); - const std::string &Str = S.str(); - - // If replacement succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, Str)) { - ReplacedNodes[Old] = New; - return; - } - if (SilenceRewriteMacroWarning) - return; - Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) - << Old->getSourceRange(); - } - - void InsertText(SourceLocation Loc, StringRef Str, - bool InsertAfter = true) { - // If insertion succeeded or warning disabled return with no warning. - if (!Rewrite.InsertText(Loc, Str, InsertAfter) || - SilenceRewriteMacroWarning) - return; - - Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); - } - - void ReplaceText(SourceLocation Start, unsigned OrigLength, - StringRef Str) { - // If removal succeeded or warning disabled return with no warning. - if (!Rewrite.ReplaceText(Start, OrigLength, Str) || - SilenceRewriteMacroWarning) - return; - - Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag); - } - - // Syntactic Rewriting. - void RewriteRecordBody(RecordDecl *RD); - void RewriteInclude(); - void RewriteForwardClassDecl(DeclGroupRef D); - void RewriteForwardClassDecl(const SmallVectorImpl<Decl *> &DG); - void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl, - const std::string &typedefString); - void RewriteImplementations(); - void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, - ObjCImplementationDecl *IMD, - ObjCCategoryImplDecl *CID); - void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl); - void RewriteImplementationDecl(Decl *Dcl); - void RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, - ObjCMethodDecl *MDecl, std::string &ResultStr); - void RewriteTypeIntoString(QualType T, std::string &ResultStr, - const FunctionType *&FPRetType); - void RewriteByRefString(std::string &ResultStr, const std::string &Name, - ValueDecl *VD, bool def=false); - void RewriteCategoryDecl(ObjCCategoryDecl *Dcl); - void RewriteProtocolDecl(ObjCProtocolDecl *Dcl); - void RewriteForwardProtocolDecl(DeclGroupRef D); - void RewriteForwardProtocolDecl(const SmallVectorImpl<Decl *> &DG); - void RewriteMethodDeclaration(ObjCMethodDecl *Method); - void RewriteProperty(ObjCPropertyDecl *prop); - void RewriteFunctionDecl(FunctionDecl *FD); - void RewriteBlockPointerType(std::string& Str, QualType Type); - void RewriteBlockPointerTypeVariable(std::string& Str, ValueDecl *VD); - void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD); - void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl); - void RewriteTypeOfDecl(VarDecl *VD); - void RewriteObjCQualifiedInterfaceTypes(Expr *E); - - // Expression Rewriting. - Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S); - Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp); - Stmt *RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseudo); - Stmt *RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseudo); - Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp); - Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp); - Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp); - Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp); - void RewriteTryReturnStmts(Stmt *S); - void RewriteSyncReturnStmts(Stmt *S, std::string buf); - Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); - Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); - Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S); - Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, - SourceLocation OrigEnd); - Stmt *RewriteBreakStmt(BreakStmt *S); - Stmt *RewriteContinueStmt(ContinueStmt *S); - void RewriteCastExpr(CStyleCastExpr *CE); - - // Block rewriting. - void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D); - - // Block specific rewrite rules. - void RewriteBlockPointerDecl(NamedDecl *VD); - void RewriteByRefVar(VarDecl *VD); - Stmt *RewriteBlockDeclRefExpr(DeclRefExpr *VD); - Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE); - void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); - - void RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, - std::string &Result); - - virtual void Initialize(ASTContext &context) override = 0; - - // Metadata Rewriting. - virtual void RewriteMetaDataIntoBuffer(std::string &Result) = 0; - virtual void RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Prots, - StringRef prefix, - StringRef ClassName, - std::string &Result) = 0; - virtual void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl, - std::string &Result) = 0; - virtual void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol, - StringRef prefix, - StringRef ClassName, - std::string &Result) = 0; - virtual void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, - std::string &Result) = 0; - - // Rewriting ivar access - virtual Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) = 0; - virtual void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, - std::string &Result) = 0; - - // Misc. AST transformation routines. Sometimes they end up calling - // rewriting routines on the new ASTs. - CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD, - Expr **args, unsigned nargs, - SourceLocation StartLoc=SourceLocation(), - SourceLocation EndLoc=SourceLocation()); - CallExpr *SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, - QualType msgSendType, - QualType returnType, - SmallVectorImpl<QualType> &ArgTypes, - SmallVectorImpl<Expr*> &MsgExprs, - ObjCMethodDecl *Method); - Stmt *SynthMessageExpr(ObjCMessageExpr *Exp, - SourceLocation StartLoc=SourceLocation(), - SourceLocation EndLoc=SourceLocation()); - - void SynthCountByEnumWithState(std::string &buf); - void SynthMsgSendFunctionDecl(); - void SynthMsgSendSuperFunctionDecl(); - void SynthMsgSendStretFunctionDecl(); - void SynthMsgSendFpretFunctionDecl(); - void SynthMsgSendSuperStretFunctionDecl(); - void SynthGetClassFunctionDecl(); - void SynthGetMetaClassFunctionDecl(); - void SynthGetSuperClassFunctionDecl(); - void SynthSelGetUidFunctionDecl(); - void SynthSuperConstructorFunctionDecl(); - - std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag); - std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - StringRef funcName, std::string Tag); - std::string SynthesizeBlockFunc(BlockExpr *CE, int i, - StringRef funcName, std::string Tag); - std::string SynthesizeBlockImpl(BlockExpr *CE, - std::string Tag, std::string Desc); - std::string SynthesizeBlockDescriptor(std::string DescTag, - std::string ImplTag, - int i, StringRef funcName, - unsigned hasCopy); - Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp); - void SynthesizeBlockLiterals(SourceLocation FunLocStart, - StringRef FunName); - FunctionDecl *SynthBlockInitFunctionDecl(StringRef name); - Stmt *SynthBlockInitExpr(BlockExpr *Exp, - const SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs); - - // Misc. helper routines. - QualType getProtocolType(); - void WarnAboutReturnGotoStmts(Stmt *S); - void HasReturnStmts(Stmt *S, bool &hasReturns); - void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND); - void InsertBlockLiteralsWithinFunction(FunctionDecl *FD); - void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD); - - bool IsDeclStmtInForeachHeader(DeclStmt *DS); - void CollectBlockDeclRefInfo(BlockExpr *Exp); - void GetBlockDeclRefExprs(Stmt *S); - void GetInnerBlockDeclRefExprs(Stmt *S, - SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs, - llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts); - - // We avoid calling Type::isBlockPointerType(), since it operates on the - // canonical type. We only care if the top-level type is a closure pointer. - bool isTopLevelBlockPointerType(QualType T) { - return isa<BlockPointerType>(T); - } - - /// convertBlockPointerToFunctionPointer - Converts a block-pointer type - /// to a function pointer type and upon success, returns true; false - /// otherwise. - bool convertBlockPointerToFunctionPointer(QualType &T) { - if (isTopLevelBlockPointerType(T)) { - const BlockPointerType *BPT = T->getAs<BlockPointerType>(); - T = Context->getPointerType(BPT->getPointeeType()); - return true; - } - return false; - } - - bool needToScanForQualifiers(QualType T); - QualType getSuperStructType(); - QualType getConstantStringStructType(); - QualType convertFunctionTypeOfBlocks(const FunctionType *FT); - bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf); - - void convertToUnqualifiedObjCType(QualType &T) { - if (T->isObjCQualifiedIdType()) - T = Context->getObjCIdType(); - else if (T->isObjCQualifiedClassType()) - T = Context->getObjCClassType(); - else if (T->isObjCObjectPointerType() && - T->getPointeeType()->isObjCQualifiedInterfaceType()) { - if (const ObjCObjectPointerType * OBJPT = - T->getAsObjCInterfacePointerType()) { - const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType(); - T = QualType(IFaceT, 0); - T = Context->getPointerType(T); - } - } - } - - // FIXME: This predicate seems like it would be useful to add to ASTContext. - bool isObjCType(QualType T) { - if (!LangOpts.ObjC1 && !LangOpts.ObjC2) - return false; - - QualType OCT = Context->getCanonicalType(T).getUnqualifiedType(); - - if (OCT == Context->getCanonicalType(Context->getObjCIdType()) || - OCT == Context->getCanonicalType(Context->getObjCClassType())) - return true; - - if (const PointerType *PT = OCT->getAs<PointerType>()) { - if (isa<ObjCInterfaceType>(PT->getPointeeType()) || - PT->getPointeeType()->isObjCQualifiedIdType()) - return true; - } - return false; - } - bool PointerTypeTakesAnyBlockArguments(QualType QT); - bool PointerTypeTakesAnyObjCQualifiedType(QualType QT); - void GetExtentOfArgList(const char *Name, const char *&LParen, - const char *&RParen); - - void QuoteDoublequotes(std::string &From, std::string &To) { - for (unsigned i = 0; i < From.length(); i++) { - if (From[i] == '"') - To += "\\\""; - else - To += From[i]; - } - } - - QualType getSimpleFunctionType(QualType result, - ArrayRef<QualType> args, - bool variadic = false) { - if (result == Context->getObjCInstanceType()) - result = Context->getObjCIdType(); - FunctionProtoType::ExtProtoInfo fpi; - fpi.Variadic = variadic; - return Context->getFunctionType(result, args, fpi); - } - - // Helper function: create a CStyleCastExpr with trivial type source info. - CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty, - CastKind Kind, Expr *E) { - TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation()); - return CStyleCastExpr::Create(*Ctx, Ty, VK_RValue, Kind, E, nullptr, - TInfo, SourceLocation(), SourceLocation()); - } - - StringLiteral *getStringLiteral(StringRef Str) { - QualType StrType = Context->getConstantArrayType( - Context->CharTy, llvm::APInt(32, Str.size() + 1), ArrayType::Normal, - 0); - return StringLiteral::Create(*Context, Str, StringLiteral::Ascii, - /*Pascal=*/false, StrType, SourceLocation()); - } - }; - - class RewriteObjCFragileABI : public RewriteObjC { - public: - - RewriteObjCFragileABI(std::string inFile, raw_ostream *OS, - DiagnosticsEngine &D, const LangOptions &LOpts, - bool silenceMacroWarn) : RewriteObjC(inFile, OS, - D, LOpts, - silenceMacroWarn) {} - - ~RewriteObjCFragileABI() {} - virtual void Initialize(ASTContext &context) override; - - // Rewriting metadata - template<typename MethodIterator> - void RewriteObjCMethodsMetaData(MethodIterator MethodBegin, - MethodIterator MethodEnd, - bool IsInstanceMethod, - StringRef prefix, - StringRef ClassName, - std::string &Result); - void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol, - StringRef prefix, StringRef ClassName, - std::string &Result) override; - void RewriteObjCProtocolListMetaData( - const ObjCList<ObjCProtocolDecl> &Prots, - StringRef prefix, StringRef ClassName, std::string &Result) override; - void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, - std::string &Result) override; - void RewriteMetaDataIntoBuffer(std::string &Result) override; - void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl, - std::string &Result) override; - - // Rewriting ivar - void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, - std::string &Result) override; - Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) override; - }; -} - -void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType, - NamedDecl *D) { - if (const FunctionProtoType *fproto - = dyn_cast<FunctionProtoType>(funcType.IgnoreParens())) { - for (const auto &I : fproto->param_types()) - if (isTopLevelBlockPointerType(I)) { - // All the args are checked/rewritten. Don't call twice! - RewriteBlockPointerDecl(D); - break; - } - } -} - -void RewriteObjC::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) { - const PointerType *PT = funcType->getAs<PointerType>(); - if (PT && PointerTypeTakesAnyBlockArguments(funcType)) - RewriteBlocksInFunctionProtoType(PT->getPointeeType(), ND); -} - -static bool IsHeaderFile(const std::string &Filename) { - std::string::size_type DotPos = Filename.rfind('.'); - - if (DotPos == std::string::npos) { - // no file extension - return false; - } - - std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end()); - // C header: .h - // C++ header: .hh or .H; - return Ext == "h" || Ext == "hh" || Ext == "H"; -} - -RewriteObjC::RewriteObjC(std::string inFile, raw_ostream* OS, - DiagnosticsEngine &D, const LangOptions &LOpts, - bool silenceMacroWarn) - : Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS), - SilenceRewriteMacroWarning(silenceMacroWarn) { - IsHeader = IsHeaderFile(inFile); - RewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning, - "rewriting sub-expression within a macro (may not be correct)"); - TryFinallyContainsReturnDiag = Diags.getCustomDiagID( - DiagnosticsEngine::Warning, - "rewriter doesn't support user-specified control flow semantics " - "for @try/@finally (code may not execute properly)"); -} - -ASTConsumer *clang::CreateObjCRewriter(const std::string& InFile, - raw_ostream* OS, - DiagnosticsEngine &Diags, - const LangOptions &LOpts, - bool SilenceRewriteMacroWarning) { - return new RewriteObjCFragileABI(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning); -} - -void RewriteObjC::InitializeCommon(ASTContext &context) { - Context = &context; - SM = &Context->getSourceManager(); - TUDecl = Context->getTranslationUnitDecl(); - MsgSendFunctionDecl = nullptr; - MsgSendSuperFunctionDecl = nullptr; - MsgSendStretFunctionDecl = nullptr; - MsgSendSuperStretFunctionDecl = nullptr; - MsgSendFpretFunctionDecl = nullptr; - GetClassFunctionDecl = nullptr; - GetMetaClassFunctionDecl = nullptr; - GetSuperClassFunctionDecl = nullptr; - SelGetUidFunctionDecl = nullptr; - CFStringFunctionDecl = nullptr; - ConstantStringClassReference = nullptr; - NSStringRecord = nullptr; - CurMethodDef = nullptr; - CurFunctionDef = nullptr; - CurFunctionDeclToDeclareForBlock = nullptr; - GlobalVarDecl = nullptr; - SuperStructDecl = nullptr; - ProtocolTypeDecl = nullptr; - ConstantStringDecl = nullptr; - BcLabelCount = 0; - SuperConstructorFunctionDecl = nullptr; - NumObjCStringLiterals = 0; - PropParentMap = nullptr; - CurrentBody = nullptr; - DisableReplaceStmt = false; - objc_impl_method = false; - - // Get the ID and start/end of the main file. - MainFileID = SM->getMainFileID(); - const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID); - MainFileStart = MainBuf->getBufferStart(); - MainFileEnd = MainBuf->getBufferEnd(); - - Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOpts()); -} - -//===----------------------------------------------------------------------===// -// Top Level Driver Code -//===----------------------------------------------------------------------===// - -void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) { - if (Diags.hasErrorOccurred()) - return; - - // Two cases: either the decl could be in the main file, or it could be in a - // #included file. If the former, rewrite it now. If the later, check to see - // if we rewrote the #include/#import. - SourceLocation Loc = D->getLocation(); - Loc = SM->getExpansionLoc(Loc); - - // If this is for a builtin, ignore it. - if (Loc.isInvalid()) return; - - // Look for built-in declarations that we need to refer during the rewrite. - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - RewriteFunctionDecl(FD); - } else if (VarDecl *FVD = dyn_cast<VarDecl>(D)) { - // declared in <Foundation/NSString.h> - if (FVD->getName() == "_NSConstantStringClassReference") { - ConstantStringClassReference = FVD; - return; - } - } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) { - if (ID->isThisDeclarationADefinition()) - RewriteInterfaceDecl(ID); - } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) { - RewriteCategoryDecl(CD); - } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) { - if (PD->isThisDeclarationADefinition()) - RewriteProtocolDecl(PD); - } else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) { - // Recurse into linkage specifications - for (DeclContext::decl_iterator DI = LSD->decls_begin(), - DIEnd = LSD->decls_end(); - DI != DIEnd; ) { - if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>((*DI))) { - if (!IFace->isThisDeclarationADefinition()) { - SmallVector<Decl *, 8> DG; - SourceLocation StartLoc = IFace->getLocStart(); - do { - if (isa<ObjCInterfaceDecl>(*DI) && - !cast<ObjCInterfaceDecl>(*DI)->isThisDeclarationADefinition() && - StartLoc == (*DI)->getLocStart()) - DG.push_back(*DI); - else - break; - - ++DI; - } while (DI != DIEnd); - RewriteForwardClassDecl(DG); - continue; - } - } - - if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>((*DI))) { - if (!Proto->isThisDeclarationADefinition()) { - SmallVector<Decl *, 8> DG; - SourceLocation StartLoc = Proto->getLocStart(); - do { - if (isa<ObjCProtocolDecl>(*DI) && - !cast<ObjCProtocolDecl>(*DI)->isThisDeclarationADefinition() && - StartLoc == (*DI)->getLocStart()) - DG.push_back(*DI); - else - break; - - ++DI; - } while (DI != DIEnd); - RewriteForwardProtocolDecl(DG); - continue; - } - } - - HandleTopLevelSingleDecl(*DI); - ++DI; - } - } - // If we have a decl in the main file, see if we should rewrite it. - if (SM->isWrittenInMainFile(Loc)) - return HandleDeclInMainFile(D); -} - -//===----------------------------------------------------------------------===// -// Syntactic (non-AST) Rewriting Code -//===----------------------------------------------------------------------===// - -void RewriteObjC::RewriteInclude() { - SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID); - StringRef MainBuf = SM->getBufferData(MainFileID); - const char *MainBufStart = MainBuf.begin(); - const char *MainBufEnd = MainBuf.end(); - size_t ImportLen = strlen("import"); - - // Loop over the whole file, looking for includes. - for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) { - if (*BufPtr == '#') { - if (++BufPtr == MainBufEnd) - return; - while (*BufPtr == ' ' || *BufPtr == '\t') - if (++BufPtr == MainBufEnd) - return; - if (!strncmp(BufPtr, "import", ImportLen)) { - // replace import with include - SourceLocation ImportLoc = - LocStart.getLocWithOffset(BufPtr-MainBufStart); - ReplaceText(ImportLoc, ImportLen, "include"); - BufPtr += ImportLen; - } - } - } -} - -static std::string getIvarAccessString(ObjCIvarDecl *OID) { - const ObjCInterfaceDecl *ClassDecl = OID->getContainingInterface(); - std::string S; - S = "((struct "; - S += ClassDecl->getIdentifier()->getName(); - S += "_IMPL *)self)->"; - S += OID->getName(); - return S; -} - -void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, - ObjCImplementationDecl *IMD, - ObjCCategoryImplDecl *CID) { - static bool objcGetPropertyDefined = false; - static bool objcSetPropertyDefined = false; - SourceLocation startLoc = PID->getLocStart(); - InsertText(startLoc, "// "); - const char *startBuf = SM->getCharacterData(startLoc); - assert((*startBuf == '@') && "bogus @synthesize location"); - const char *semiBuf = strchr(startBuf, ';'); - assert((*semiBuf == ';') && "@synthesize: can't find ';'"); - SourceLocation onePastSemiLoc = - startLoc.getLocWithOffset(semiBuf-startBuf+1); - - if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - return; // FIXME: is this correct? - - // Generate the 'getter' function. - ObjCPropertyDecl *PD = PID->getPropertyDecl(); - ObjCIvarDecl *OID = PID->getPropertyIvarDecl(); - - if (!OID) - return; - unsigned Attributes = PD->getPropertyAttributes(); - if (!PD->getGetterMethodDecl()->isDefined()) { - bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) && - (Attributes & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy)); - std::string Getr; - if (GenGetProperty && !objcGetPropertyDefined) { - objcGetPropertyDefined = true; - // FIXME. Is this attribute correct in all cases? - Getr = "\nextern \"C\" __declspec(dllimport) " - "id objc_getProperty(id, SEL, long, bool);\n"; - } - RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getGetterMethodDecl(), Getr); - Getr += "{ "; - // Synthesize an explicit cast to gain access to the ivar. - // See objc-act.c:objc_synthesize_new_getter() for details. - if (GenGetProperty) { - // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) - Getr += "typedef "; - const FunctionType *FPRetType = nullptr; - RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr, - FPRetType); - Getr += " _TYPE"; - if (FPRetType) { - Getr += ")"; // close the precedence "scope" for "*". - - // Now, emit the argument types (if any). - if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)){ - Getr += "("; - for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { - if (i) Getr += ", "; - std::string ParamStr = - FT->getParamType(i).getAsString(Context->getPrintingPolicy()); - Getr += ParamStr; - } - if (FT->isVariadic()) { - if (FT->getNumParams()) - Getr += ", "; - Getr += "..."; - } - Getr += ")"; - } else - Getr += "()"; - } - Getr += ";\n"; - Getr += "return (_TYPE)"; - Getr += "objc_getProperty(self, _cmd, "; - RewriteIvarOffsetComputation(OID, Getr); - Getr += ", 1)"; - } - else - Getr += "return " + getIvarAccessString(OID); - Getr += "; }"; - InsertText(onePastSemiLoc, Getr); - } - - if (PD->isReadOnly() || PD->getSetterMethodDecl()->isDefined()) - return; - - // Generate the 'setter' function. - std::string Setr; - bool GenSetProperty = Attributes & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy); - if (GenSetProperty && !objcSetPropertyDefined) { - objcSetPropertyDefined = true; - // FIXME. Is this attribute correct in all cases? - Setr = "\nextern \"C\" __declspec(dllimport) " - "void objc_setProperty (id, SEL, long, id, bool, bool);\n"; - } - - RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getSetterMethodDecl(), Setr); - Setr += "{ "; - // Synthesize an explicit cast to initialize the ivar. - // See objc-act.c:objc_synthesize_new_setter() for details. - if (GenSetProperty) { - Setr += "objc_setProperty (self, _cmd, "; - RewriteIvarOffsetComputation(OID, Setr); - Setr += ", (id)"; - Setr += PD->getName(); - Setr += ", "; - if (Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) - Setr += "0, "; - else - Setr += "1, "; - if (Attributes & ObjCPropertyDecl::OBJC_PR_copy) - Setr += "1)"; - else - Setr += "0)"; - } - else { - Setr += getIvarAccessString(OID) + " = "; - Setr += PD->getName(); - } - Setr += "; }"; - InsertText(onePastSemiLoc, Setr); -} - -static void RewriteOneForwardClassDecl(ObjCInterfaceDecl *ForwardDecl, - std::string &typedefString) { - typedefString += "#ifndef _REWRITER_typedef_"; - typedefString += ForwardDecl->getNameAsString(); - typedefString += "\n"; - typedefString += "#define _REWRITER_typedef_"; - typedefString += ForwardDecl->getNameAsString(); - typedefString += "\n"; - typedefString += "typedef struct objc_object "; - typedefString += ForwardDecl->getNameAsString(); - typedefString += ";\n#endif\n"; -} - -void RewriteObjC::RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl, - const std::string &typedefString) { - SourceLocation startLoc = ClassDecl->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - const char *semiPtr = strchr(startBuf, ';'); - // Replace the @class with typedefs corresponding to the classes. - ReplaceText(startLoc, semiPtr-startBuf+1, typedefString); -} - -void RewriteObjC::RewriteForwardClassDecl(DeclGroupRef D) { - std::string typedefString; - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { - ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(*I); - if (I == D.begin()) { - // Translate to typedef's that forward reference structs with the same name - // as the class. As a convenience, we include the original declaration - // as a comment. - typedefString += "// @class "; - typedefString += ForwardDecl->getNameAsString(); - typedefString += ";\n"; - } - RewriteOneForwardClassDecl(ForwardDecl, typedefString); - } - DeclGroupRef::iterator I = D.begin(); - RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(*I), typedefString); -} - -void RewriteObjC::RewriteForwardClassDecl(const SmallVectorImpl<Decl *> &D) { - std::string typedefString; - for (unsigned i = 0; i < D.size(); i++) { - ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(D[i]); - if (i == 0) { - typedefString += "// @class "; - typedefString += ForwardDecl->getNameAsString(); - typedefString += ";\n"; - } - RewriteOneForwardClassDecl(ForwardDecl, typedefString); - } - RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(D[0]), typedefString); -} - -void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { - // When method is a synthesized one, such as a getter/setter there is - // nothing to rewrite. - if (Method->isImplicit()) - return; - SourceLocation LocStart = Method->getLocStart(); - SourceLocation LocEnd = Method->getLocEnd(); - - if (SM->getExpansionLineNumber(LocEnd) > - SM->getExpansionLineNumber(LocStart)) { - InsertText(LocStart, "#if 0\n"); - ReplaceText(LocEnd, 1, ";\n#endif\n"); - } else { - InsertText(LocStart, "// "); - } -} - -void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop) { - SourceLocation Loc = prop->getAtLoc(); - - ReplaceText(Loc, 0, "// "); - // FIXME: handle properties that are declared across multiple lines. -} - -void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { - SourceLocation LocStart = CatDecl->getLocStart(); - - // FIXME: handle category headers that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); - - for (auto *I : CatDecl->properties()) - RewriteProperty(I); - for (auto *I : CatDecl->instance_methods()) - RewriteMethodDeclaration(I); - for (auto *I : CatDecl->class_methods()) - RewriteMethodDeclaration(I); - - // Lastly, comment out the @end. - ReplaceText(CatDecl->getAtEndRange().getBegin(), - strlen("@end"), "/* @end */"); -} - -void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { - SourceLocation LocStart = PDecl->getLocStart(); - assert(PDecl->isThisDeclarationADefinition()); - - // FIXME: handle protocol headers that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); - - for (auto *I : PDecl->instance_methods()) - RewriteMethodDeclaration(I); - for (auto *I : PDecl->class_methods()) - RewriteMethodDeclaration(I); - for (auto *I : PDecl->properties()) - RewriteProperty(I); - - // Lastly, comment out the @end. - SourceLocation LocEnd = PDecl->getAtEndRange().getBegin(); - ReplaceText(LocEnd, strlen("@end"), "/* @end */"); - - // Must comment out @optional/@required - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - for (const char *p = startBuf; p < endBuf; p++) { - if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) { - SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); - ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */"); - - } - else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) { - SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf); - ReplaceText(OptionalLoc, strlen("@required"), "/* @required */"); - - } - } -} - -void RewriteObjC::RewriteForwardProtocolDecl(DeclGroupRef D) { - SourceLocation LocStart = (*D.begin())->getLocStart(); - if (LocStart.isInvalid()) - llvm_unreachable("Invalid SourceLocation"); - // FIXME: handle forward protocol that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); -} - -void -RewriteObjC::RewriteForwardProtocolDecl(const SmallVectorImpl<Decl *> &DG) { - SourceLocation LocStart = DG[0]->getLocStart(); - if (LocStart.isInvalid()) - llvm_unreachable("Invalid SourceLocation"); - // FIXME: handle forward protocol that are declared across multiple lines. - ReplaceText(LocStart, 0, "// "); -} - -void RewriteObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr, - const FunctionType *&FPRetType) { - if (T->isObjCQualifiedIdType()) - ResultStr += "id"; - else if (T->isFunctionPointerType() || - T->isBlockPointerType()) { - // needs special handling, since pointer-to-functions have special - // syntax (where a decaration models use). - QualType retType = T; - QualType PointeeTy; - if (const PointerType* PT = retType->getAs<PointerType>()) - PointeeTy = PT->getPointeeType(); - else if (const BlockPointerType *BPT = retType->getAs<BlockPointerType>()) - PointeeTy = BPT->getPointeeType(); - if ((FPRetType = PointeeTy->getAs<FunctionType>())) { - ResultStr += - FPRetType->getReturnType().getAsString(Context->getPrintingPolicy()); - ResultStr += "(*"; - } - } else - ResultStr += T.getAsString(Context->getPrintingPolicy()); -} - -void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl, - ObjCMethodDecl *OMD, - std::string &ResultStr) { - //fprintf(stderr,"In RewriteObjCMethodDecl\n"); - const FunctionType *FPRetType = nullptr; - ResultStr += "\nstatic "; - RewriteTypeIntoString(OMD->getReturnType(), ResultStr, FPRetType); - ResultStr += " "; - - // Unique method name - std::string NameStr; - - if (OMD->isInstanceMethod()) - NameStr += "_I_"; - else - NameStr += "_C_"; - - NameStr += IDecl->getNameAsString(); - NameStr += "_"; - - if (ObjCCategoryImplDecl *CID = - dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) { - NameStr += CID->getNameAsString(); - NameStr += "_"; - } - // Append selector names, replacing ':' with '_' - { - std::string selString = OMD->getSelector().getAsString(); - int len = selString.size(); - for (int i = 0; i < len; i++) - if (selString[i] == ':') - selString[i] = '_'; - NameStr += selString; - } - // Remember this name for metadata emission - MethodInternalNames[OMD] = NameStr; - ResultStr += NameStr; - - // Rewrite arguments - ResultStr += "("; - - // invisible arguments - if (OMD->isInstanceMethod()) { - QualType selfTy = Context->getObjCInterfaceType(IDecl); - selfTy = Context->getPointerType(selfTy); - if (!LangOpts.MicrosoftExt) { - if (ObjCSynthesizedStructs.count(const_cast<ObjCInterfaceDecl*>(IDecl))) - ResultStr += "struct "; - } - // When rewriting for Microsoft, explicitly omit the structure name. - ResultStr += IDecl->getNameAsString(); - ResultStr += " *"; - } - else - ResultStr += Context->getObjCClassType().getAsString( - Context->getPrintingPolicy()); - - ResultStr += " self, "; - ResultStr += Context->getObjCSelType().getAsString(Context->getPrintingPolicy()); - ResultStr += " _cmd"; - - // Method arguments. - for (const auto *PDecl : OMD->params()) { - ResultStr += ", "; - if (PDecl->getType()->isObjCQualifiedIdType()) { - ResultStr += "id "; - ResultStr += PDecl->getNameAsString(); - } else { - std::string Name = PDecl->getNameAsString(); - QualType QT = PDecl->getType(); - // Make sure we convert "t (^)(...)" to "t (*)(...)". - (void)convertBlockPointerToFunctionPointer(QT); - QT.getAsStringInternal(Name, Context->getPrintingPolicy()); - ResultStr += Name; - } - } - if (OMD->isVariadic()) - ResultStr += ", ..."; - ResultStr += ") "; - - if (FPRetType) { - ResultStr += ")"; // close the precedence "scope" for "*". - - // Now, emit the argument types (if any). - if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)) { - ResultStr += "("; - for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { - if (i) ResultStr += ", "; - std::string ParamStr = - FT->getParamType(i).getAsString(Context->getPrintingPolicy()); - ResultStr += ParamStr; - } - if (FT->isVariadic()) { - if (FT->getNumParams()) - ResultStr += ", "; - ResultStr += "..."; - } - ResultStr += ")"; - } else { - ResultStr += "()"; - } - } -} -void RewriteObjC::RewriteImplementationDecl(Decl *OID) { - ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID); - ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID); - - InsertText(IMD ? IMD->getLocStart() : CID->getLocStart(), "// "); - - for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) { - std::string ResultStr; - RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); - SourceLocation LocStart = OMD->getLocStart(); - SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - ReplaceText(LocStart, endBuf-startBuf, ResultStr); - } - - for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) { - std::string ResultStr; - RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); - SourceLocation LocStart = OMD->getLocStart(); - SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - ReplaceText(LocStart, endBuf-startBuf, ResultStr); - } - for (auto *I : IMD ? IMD->property_impls() : CID->property_impls()) - RewritePropertyImplDecl(I, IMD, CID); - - InsertText(IMD ? IMD->getLocEnd() : CID->getLocEnd(), "// "); -} - -void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { - std::string ResultStr; - if (!ObjCForwardDecls.count(ClassDecl->getCanonicalDecl())) { - // we haven't seen a forward decl - generate a typedef. - ResultStr = "#ifndef _REWRITER_typedef_"; - ResultStr += ClassDecl->getNameAsString(); - ResultStr += "\n"; - ResultStr += "#define _REWRITER_typedef_"; - ResultStr += ClassDecl->getNameAsString(); - ResultStr += "\n"; - ResultStr += "typedef struct objc_object "; - ResultStr += ClassDecl->getNameAsString(); - ResultStr += ";\n#endif\n"; - // Mark this typedef as having been generated. - ObjCForwardDecls.insert(ClassDecl->getCanonicalDecl()); - } - RewriteObjCInternalStruct(ClassDecl, ResultStr); - - for (auto *I : ClassDecl->properties()) - RewriteProperty(I); - for (auto *I : ClassDecl->instance_methods()) - RewriteMethodDeclaration(I); - for (auto *I : ClassDecl->class_methods()) - RewriteMethodDeclaration(I); - - // Lastly, comment out the @end. - ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"), - "/* @end */"); -} - -Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *PseudoOp) { - SourceRange OldRange = PseudoOp->getSourceRange(); - - // We just magically know some things about the structure of this - // expression. - ObjCMessageExpr *OldMsg = - cast<ObjCMessageExpr>(PseudoOp->getSemanticExpr( - PseudoOp->getNumSemanticExprs() - 1)); - - // Because the rewriter doesn't allow us to rewrite rewritten code, - // we need to suppress rewriting the sub-statements. - Expr *Base, *RHS; - { - DisableReplaceStmtScope S(*this); - - // Rebuild the base expression if we have one. - Base = nullptr; - if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) { - Base = OldMsg->getInstanceReceiver(); - Base = cast<OpaqueValueExpr>(Base)->getSourceExpr(); - Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base)); - } - - // Rebuild the RHS. - RHS = cast<BinaryOperator>(PseudoOp->getSyntacticForm())->getRHS(); - RHS = cast<OpaqueValueExpr>(RHS)->getSourceExpr(); - RHS = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(RHS)); - } - - // TODO: avoid this copy. - SmallVector<SourceLocation, 1> SelLocs; - OldMsg->getSelectorLocs(SelLocs); - - ObjCMessageExpr *NewMsg = nullptr; - switch (OldMsg->getReceiverKind()) { - case ObjCMessageExpr::Class: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getClassReceiverTypeInfo(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - RHS, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::Instance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - Base, - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - RHS, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::SuperClass: - case ObjCMessageExpr::SuperInstance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getSuperLoc(), - OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance, - OldMsg->getSuperType(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - RHS, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - } - - Stmt *Replacement = SynthMessageExpr(NewMsg); - ReplaceStmtWithRange(PseudoOp, Replacement, OldRange); - return Replacement; -} - -Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *PseudoOp) { - SourceRange OldRange = PseudoOp->getSourceRange(); - - // We just magically know some things about the structure of this - // expression. - ObjCMessageExpr *OldMsg = - cast<ObjCMessageExpr>(PseudoOp->getResultExpr()->IgnoreImplicit()); - - // Because the rewriter doesn't allow us to rewrite rewritten code, - // we need to suppress rewriting the sub-statements. - Expr *Base = nullptr; - { - DisableReplaceStmtScope S(*this); - - // Rebuild the base expression if we have one. - if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) { - Base = OldMsg->getInstanceReceiver(); - Base = cast<OpaqueValueExpr>(Base)->getSourceExpr(); - Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base)); - } - } - - // Intentionally empty. - SmallVector<SourceLocation, 1> SelLocs; - SmallVector<Expr*, 1> Args; - - ObjCMessageExpr *NewMsg = nullptr; - switch (OldMsg->getReceiverKind()) { - case ObjCMessageExpr::Class: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getClassReceiverTypeInfo(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::Instance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - Base, - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - - case ObjCMessageExpr::SuperClass: - case ObjCMessageExpr::SuperInstance: - NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(), - OldMsg->getValueKind(), - OldMsg->getLeftLoc(), - OldMsg->getSuperLoc(), - OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance, - OldMsg->getSuperType(), - OldMsg->getSelector(), - SelLocs, - OldMsg->getMethodDecl(), - Args, - OldMsg->getRightLoc(), - OldMsg->isImplicit()); - break; - } - - Stmt *Replacement = SynthMessageExpr(NewMsg); - ReplaceStmtWithRange(PseudoOp, Replacement, OldRange); - return Replacement; -} - -/// SynthCountByEnumWithState - To print: -/// ((unsigned int (*) -/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) -/// (void *)objc_msgSend)((id)l_collection, -/// sel_registerName( -/// "countByEnumeratingWithState:objects:count:"), -/// &enumState, -/// (id *)__rw_items, (unsigned int)16) -/// -void RewriteObjC::SynthCountByEnumWithState(std::string &buf) { - buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, " - "id *, unsigned int))(void *)objc_msgSend)"; - buf += "\n\t\t"; - buf += "((id)l_collection,\n\t\t"; - buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),"; - buf += "\n\t\t"; - buf += "&enumState, " - "(id *)__rw_items, (unsigned int)16)"; -} - -/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach -/// statement to exit to its outer synthesized loop. -/// -Stmt *RewriteObjC::RewriteBreakStmt(BreakStmt *S) { - if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back())) - return S; - // replace break with goto __break_label - std::string buf; - - SourceLocation startLoc = S->getLocStart(); - buf = "goto __break_label_"; - buf += utostr(ObjCBcLabelNo.back()); - ReplaceText(startLoc, strlen("break"), buf); - - return nullptr; -} - -/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach -/// statement to continue with its inner synthesized loop. -/// -Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) { - if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back())) - return S; - // replace continue with goto __continue_label - std::string buf; - - SourceLocation startLoc = S->getLocStart(); - buf = "goto __continue_label_"; - buf += utostr(ObjCBcLabelNo.back()); - ReplaceText(startLoc, strlen("continue"), buf); - - return nullptr; -} - -/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement. -/// It rewrites: -/// for ( type elem in collection) { stmts; } - -/// Into: -/// { -/// type elem; -/// struct __objcFastEnumerationState enumState = { 0 }; -/// id __rw_items[16]; -/// id l_collection = (id)collection; -/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState -/// objects:__rw_items count:16]; -/// if (limit) { -/// unsigned long startMutations = *enumState.mutationsPtr; -/// do { -/// unsigned long counter = 0; -/// do { -/// if (startMutations != *enumState.mutationsPtr) -/// objc_enumerationMutation(l_collection); -/// elem = (type)enumState.itemsPtr[counter++]; -/// stmts; -/// __continue_label: ; -/// } while (counter < limit); -/// } while (limit = [l_collection countByEnumeratingWithState:&enumState -/// objects:__rw_items count:16]); -/// elem = nil; -/// __break_label: ; -/// } -/// else -/// elem = nil; -/// } -/// -Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, - SourceLocation OrigEnd) { - assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty"); - assert(isa<ObjCForCollectionStmt>(Stmts.back()) && - "ObjCForCollectionStmt Statement stack mismatch"); - assert(!ObjCBcLabelNo.empty() && - "ObjCForCollectionStmt - Label No stack empty"); - - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - StringRef elementName; - std::string elementTypeAsString; - std::string buf; - buf = "\n{\n\t"; - if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) { - // type elem; - NamedDecl* D = cast<NamedDecl>(DS->getSingleDecl()); - QualType ElementType = cast<ValueDecl>(D)->getType(); - if (ElementType->isObjCQualifiedIdType() || - ElementType->isObjCQualifiedInterfaceType()) - // Simply use 'id' for all qualified types. - elementTypeAsString = "id"; - else - elementTypeAsString = ElementType.getAsString(Context->getPrintingPolicy()); - buf += elementTypeAsString; - buf += " "; - elementName = D->getName(); - buf += elementName; - buf += ";\n\t"; - } - else { - DeclRefExpr *DR = cast<DeclRefExpr>(S->getElement()); - elementName = DR->getDecl()->getName(); - ValueDecl *VD = cast<ValueDecl>(DR->getDecl()); - if (VD->getType()->isObjCQualifiedIdType() || - VD->getType()->isObjCQualifiedInterfaceType()) - // Simply use 'id' for all qualified types. - elementTypeAsString = "id"; - else - elementTypeAsString = VD->getType().getAsString(Context->getPrintingPolicy()); - } - - // struct __objcFastEnumerationState enumState = { 0 }; - buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t"; - // id __rw_items[16]; - buf += "id __rw_items[16];\n\t"; - // id l_collection = (id) - buf += "id l_collection = (id)"; - // Find start location of 'collection' the hard way! - const char *startCollectionBuf = startBuf; - startCollectionBuf += 3; // skip 'for' - startCollectionBuf = strchr(startCollectionBuf, '('); - startCollectionBuf++; // skip '(' - // find 'in' and skip it. - while (*startCollectionBuf != ' ' || - *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' || - (*(startCollectionBuf+3) != ' ' && - *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '(')) - startCollectionBuf++; - startCollectionBuf += 3; - - // Replace: "for (type element in" with string constructed thus far. - ReplaceText(startLoc, startCollectionBuf - startBuf, buf); - // Replace ')' in for '(' type elem in collection ')' with ';' - SourceLocation rightParenLoc = S->getRParenLoc(); - const char *rparenBuf = SM->getCharacterData(rightParenLoc); - SourceLocation lparenLoc = startLoc.getLocWithOffset(rparenBuf-startBuf); - buf = ";\n\t"; - - // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState - // objects:__rw_items count:16]; - // which is synthesized into: - // unsigned int limit = - // ((unsigned int (*) - // (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) - // (void *)objc_msgSend)((id)l_collection, - // sel_registerName( - // "countByEnumeratingWithState:objects:count:"), - // (struct __objcFastEnumerationState *)&state, - // (id *)__rw_items, (unsigned int)16); - buf += "unsigned long limit =\n\t\t"; - SynthCountByEnumWithState(buf); - buf += ";\n\t"; - /// if (limit) { - /// unsigned long startMutations = *enumState.mutationsPtr; - /// do { - /// unsigned long counter = 0; - /// do { - /// if (startMutations != *enumState.mutationsPtr) - /// objc_enumerationMutation(l_collection); - /// elem = (type)enumState.itemsPtr[counter++]; - buf += "if (limit) {\n\t"; - buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t"; - buf += "do {\n\t\t"; - buf += "unsigned long counter = 0;\n\t\t"; - buf += "do {\n\t\t\t"; - buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t"; - buf += "objc_enumerationMutation(l_collection);\n\t\t\t"; - buf += elementName; - buf += " = ("; - buf += elementTypeAsString; - buf += ")enumState.itemsPtr[counter++];"; - // Replace ')' in for '(' type elem in collection ')' with all of these. - ReplaceText(lparenLoc, 1, buf); - - /// __continue_label: ; - /// } while (counter < limit); - /// } while (limit = [l_collection countByEnumeratingWithState:&enumState - /// objects:__rw_items count:16]); - /// elem = nil; - /// __break_label: ; - /// } - /// else - /// elem = nil; - /// } - /// - buf = ";\n\t"; - buf += "__continue_label_"; - buf += utostr(ObjCBcLabelNo.back()); - buf += ": ;"; - buf += "\n\t\t"; - buf += "} while (counter < limit);\n\t"; - buf += "} while (limit = "; - SynthCountByEnumWithState(buf); - buf += ");\n\t"; - buf += elementName; - buf += " = (("; - buf += elementTypeAsString; - buf += ")0);\n\t"; - buf += "__break_label_"; - buf += utostr(ObjCBcLabelNo.back()); - buf += ": ;\n\t"; - buf += "}\n\t"; - buf += "else\n\t\t"; - buf += elementName; - buf += " = (("; - buf += elementTypeAsString; - buf += ")0);\n\t"; - buf += "}\n"; - - // Insert all these *after* the statement body. - // FIXME: If this should support Obj-C++, support CXXTryStmt - if (isa<CompoundStmt>(S->getBody())) { - SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(1); - InsertText(endBodyLoc, buf); - } else { - /* Need to treat single statements specially. For example: - * - * for (A *a in b) if (stuff()) break; - * for (A *a in b) xxxyy; - * - * The following code simply scans ahead to the semi to find the actual end. - */ - const char *stmtBuf = SM->getCharacterData(OrigEnd); - const char *semiBuf = strchr(stmtBuf, ';'); - assert(semiBuf && "Can't find ';'"); - SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(semiBuf-stmtBuf+1); - InsertText(endBodyLoc, buf); - } - Stmts.pop_back(); - ObjCBcLabelNo.pop_back(); - return nullptr; -} - -/// RewriteObjCSynchronizedStmt - -/// This routine rewrites @synchronized(expr) stmt; -/// into: -/// objc_sync_enter(expr); -/// @try stmt @finally { objc_sync_exit(expr); } -/// -Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @synchronized location"); - - std::string buf; - buf = "objc_sync_enter((id)"; - const char *lparenBuf = startBuf; - while (*lparenBuf != '(') lparenBuf++; - ReplaceText(startLoc, lparenBuf-startBuf+1, buf); - // We can't use S->getSynchExpr()->getLocEnd() to find the end location, since - // the sync expression is typically a message expression that's already - // been rewritten! (which implies the SourceLocation's are invalid). - SourceLocation endLoc = S->getSynchBody()->getLocStart(); - const char *endBuf = SM->getCharacterData(endLoc); - while (*endBuf != ')') endBuf--; - SourceLocation rparenLoc = startLoc.getLocWithOffset(endBuf-startBuf); - buf = ");\n"; - // declare a new scope with two variables, _stack and _rethrow. - buf += "/* @try scope begin */ \n{ struct _objc_exception_data {\n"; - buf += "int buf[18/*32-bit i386*/];\n"; - buf += "char *pointers[4];} _stack;\n"; - buf += "id volatile _rethrow = 0;\n"; - buf += "objc_exception_try_enter(&_stack);\n"; - buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n"; - ReplaceText(rparenLoc, 1, buf); - startLoc = S->getSynchBody()->getLocEnd(); - startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '}') && "bogus @synchronized block"); - SourceLocation lastCurlyLoc = startLoc; - buf = "}\nelse {\n"; - buf += " _rethrow = objc_exception_extract(&_stack);\n"; - buf += "}\n"; - buf += "{ /* implicit finally clause */\n"; - buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; - - std::string syncBuf; - syncBuf += " objc_sync_exit("; - - Expr *syncExpr = S->getSynchExpr(); - CastKind CK = syncExpr->getType()->isObjCObjectPointerType() - ? CK_BitCast : - syncExpr->getType()->isBlockPointerType() - ? CK_BlockPointerToObjCPointerCast - : CK_CPointerToObjCPointerCast; - syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK, syncExpr); - std::string syncExprBufS; - llvm::raw_string_ostream syncExprBuf(syncExprBufS); - assert(syncExpr != nullptr && "Expected non-null Expr"); - syncExpr->printPretty(syncExprBuf, nullptr, PrintingPolicy(LangOpts)); - syncBuf += syncExprBuf.str(); - syncBuf += ");"; - - buf += syncBuf; - buf += "\n if (_rethrow) objc_exception_throw(_rethrow);\n"; - buf += "}\n"; - buf += "}"; - - ReplaceText(lastCurlyLoc, 1, buf); - - bool hasReturns = false; - HasReturnStmts(S->getSynchBody(), hasReturns); - if (hasReturns) - RewriteSyncReturnStmts(S->getSynchBody(), syncBuf); - - return nullptr; -} - -void RewriteObjC::WarnAboutReturnGotoStmts(Stmt *S) -{ - // Perform a bottom up traversal of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) - WarnAboutReturnGotoStmts(*CI); - - if (isa<ReturnStmt>(S) || isa<GotoStmt>(S)) { - Diags.Report(Context->getFullLoc(S->getLocStart()), - TryFinallyContainsReturnDiag); - } - return; -} - -void RewriteObjC::HasReturnStmts(Stmt *S, bool &hasReturns) -{ - // Perform a bottom up traversal of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) - HasReturnStmts(*CI, hasReturns); - - if (isa<ReturnStmt>(S)) - hasReturns = true; - return; -} - -void RewriteObjC::RewriteTryReturnStmts(Stmt *S) { - // Perform a bottom up traversal of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - RewriteTryReturnStmts(*CI); - } - if (isa<ReturnStmt>(S)) { - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - const char *semiBuf = strchr(startBuf, ';'); - assert((*semiBuf == ';') && "RewriteTryReturnStmts: can't find ';'"); - SourceLocation onePastSemiLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1); - - std::string buf; - buf = "{ objc_exception_try_exit(&_stack); return"; - - ReplaceText(startLoc, 6, buf); - InsertText(onePastSemiLoc, "}"); - } - return; -} - -void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) { - // Perform a bottom up traversal of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - RewriteSyncReturnStmts(*CI, syncExitBuf); - } - if (isa<ReturnStmt>(S)) { - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - const char *semiBuf = strchr(startBuf, ';'); - assert((*semiBuf == ';') && "RewriteSyncReturnStmts: can't find ';'"); - SourceLocation onePastSemiLoc = startLoc.getLocWithOffset(semiBuf-startBuf+1); - - std::string buf; - buf = "{ objc_exception_try_exit(&_stack);"; - buf += syncExitBuf; - buf += " return"; - - ReplaceText(startLoc, 6, buf); - InsertText(onePastSemiLoc, "}"); - } - return; -} - -Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @try location"); - - std::string buf; - // declare a new scope with two variables, _stack and _rethrow. - buf = "/* @try scope begin */ { struct _objc_exception_data {\n"; - buf += "int buf[18/*32-bit i386*/];\n"; - buf += "char *pointers[4];} _stack;\n"; - buf += "id volatile _rethrow = 0;\n"; - buf += "objc_exception_try_enter(&_stack);\n"; - buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n"; - - ReplaceText(startLoc, 4, buf); - - startLoc = S->getTryBody()->getLocEnd(); - startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '}') && "bogus @try block"); - - SourceLocation lastCurlyLoc = startLoc; - if (S->getNumCatchStmts()) { - startLoc = startLoc.getLocWithOffset(1); - buf = " /* @catch begin */ else {\n"; - buf += " id _caught = objc_exception_extract(&_stack);\n"; - buf += " objc_exception_try_enter (&_stack);\n"; - buf += " if (_setjmp(_stack.buf))\n"; - buf += " _rethrow = objc_exception_extract(&_stack);\n"; - buf += " else { /* @catch continue */"; - - InsertText(startLoc, buf); - } else { /* no catch list */ - buf = "}\nelse {\n"; - buf += " _rethrow = objc_exception_extract(&_stack);\n"; - buf += "}"; - ReplaceText(lastCurlyLoc, 1, buf); - } - Stmt *lastCatchBody = nullptr; - for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { - ObjCAtCatchStmt *Catch = S->getCatchStmt(I); - VarDecl *catchDecl = Catch->getCatchParamDecl(); - - if (I == 0) - buf = "if ("; // we are generating code for the first catch clause - else - buf = "else if ("; - startLoc = Catch->getLocStart(); - startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @catch location"); - - const char *lParenLoc = strchr(startBuf, '('); - - if (Catch->hasEllipsis()) { - // Now rewrite the body... - lastCatchBody = Catch->getCatchBody(); - SourceLocation bodyLoc = lastCatchBody->getLocStart(); - const char *bodyBuf = SM->getCharacterData(bodyLoc); - assert(*SM->getCharacterData(Catch->getRParenLoc()) == ')' && - "bogus @catch paren location"); - assert((*bodyBuf == '{') && "bogus @catch body location"); - - buf += "1) { id _tmp = _caught;"; - Rewrite.ReplaceText(startLoc, bodyBuf-startBuf+1, buf); - } else if (catchDecl) { - QualType t = catchDecl->getType(); - if (t == Context->getObjCIdType()) { - buf += "1) { "; - ReplaceText(startLoc, lParenLoc-startBuf+1, buf); - } else if (const ObjCObjectPointerType *Ptr = - t->getAs<ObjCObjectPointerType>()) { - // Should be a pointer to a class. - ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface(); - if (IDecl) { - buf += "objc_exception_match((struct objc_class *)objc_getClass(\""; - buf += IDecl->getNameAsString(); - buf += "\"), (struct objc_object *)_caught)) { "; - ReplaceText(startLoc, lParenLoc-startBuf+1, buf); - } - } - // Now rewrite the body... - lastCatchBody = Catch->getCatchBody(); - SourceLocation rParenLoc = Catch->getRParenLoc(); - SourceLocation bodyLoc = lastCatchBody->getLocStart(); - const char *bodyBuf = SM->getCharacterData(bodyLoc); - const char *rParenBuf = SM->getCharacterData(rParenLoc); - assert((*rParenBuf == ')') && "bogus @catch paren location"); - assert((*bodyBuf == '{') && "bogus @catch body location"); - - // Here we replace ") {" with "= _caught;" (which initializes and - // declares the @catch parameter). - ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, " = _caught;"); - } else { - llvm_unreachable("@catch rewrite bug"); - } - } - // Complete the catch list... - if (lastCatchBody) { - SourceLocation bodyLoc = lastCatchBody->getLocEnd(); - assert(*SM->getCharacterData(bodyLoc) == '}' && - "bogus @catch body location"); - - // Insert the last (implicit) else clause *before* the right curly brace. - bodyLoc = bodyLoc.getLocWithOffset(-1); - buf = "} /* last catch end */\n"; - buf += "else {\n"; - buf += " _rethrow = _caught;\n"; - buf += " objc_exception_try_exit(&_stack);\n"; - buf += "} } /* @catch end */\n"; - if (!S->getFinallyStmt()) - buf += "}\n"; - InsertText(bodyLoc, buf); - - // Set lastCurlyLoc - lastCurlyLoc = lastCatchBody->getLocEnd(); - } - if (ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt()) { - startLoc = finalStmt->getLocStart(); - startBuf = SM->getCharacterData(startLoc); - assert((*startBuf == '@') && "bogus @finally start"); - - ReplaceText(startLoc, 8, "/* @finally */"); - - Stmt *body = finalStmt->getFinallyBody(); - SourceLocation startLoc = body->getLocStart(); - SourceLocation endLoc = body->getLocEnd(); - assert(*SM->getCharacterData(startLoc) == '{' && - "bogus @finally body location"); - assert(*SM->getCharacterData(endLoc) == '}' && - "bogus @finally body location"); - - startLoc = startLoc.getLocWithOffset(1); - InsertText(startLoc, " if (!_rethrow) objc_exception_try_exit(&_stack);\n"); - endLoc = endLoc.getLocWithOffset(-1); - InsertText(endLoc, " if (_rethrow) objc_exception_throw(_rethrow);\n"); - - // Set lastCurlyLoc - lastCurlyLoc = body->getLocEnd(); - - // Now check for any return/continue/go statements within the @try. - WarnAboutReturnGotoStmts(S->getTryBody()); - } else { /* no finally clause - make sure we synthesize an implicit one */ - buf = "{ /* implicit finally clause */\n"; - buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; - buf += " if (_rethrow) objc_exception_throw(_rethrow);\n"; - buf += "}"; - ReplaceText(lastCurlyLoc, 1, buf); - - // Now check for any return/continue/go statements within the @try. - // The implicit finally clause won't called if the @try contains any - // jump statements. - bool hasReturns = false; - HasReturnStmts(S->getTryBody(), hasReturns); - if (hasReturns) - RewriteTryReturnStmts(S->getTryBody()); - } - // Now emit the final closing curly brace... - lastCurlyLoc = lastCurlyLoc.getLocWithOffset(1); - InsertText(lastCurlyLoc, " } /* @try scope end */\n"); - return nullptr; -} - -// This can't be done with ReplaceStmt(S, ThrowExpr), since -// the throw expression is typically a message expression that's already -// been rewritten! (which implies the SourceLocation's are invalid). -Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) { - // Get the start location and compute the semi location. - SourceLocation startLoc = S->getLocStart(); - const char *startBuf = SM->getCharacterData(startLoc); - - assert((*startBuf == '@') && "bogus @throw location"); - - std::string buf; - /* void objc_exception_throw(id) __attribute__((noreturn)); */ - if (S->getThrowExpr()) - buf = "objc_exception_throw("; - else // add an implicit argument - buf = "objc_exception_throw(_caught"; - - // handle "@ throw" correctly. - const char *wBuf = strchr(startBuf, 'w'); - assert((*wBuf == 'w') && "@throw: can't find 'w'"); - ReplaceText(startLoc, wBuf-startBuf+1, buf); - - const char *semiBuf = strchr(startBuf, ';'); - assert((*semiBuf == ';') && "@throw: can't find ';'"); - SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf); - ReplaceText(semiLoc, 1, ");"); - return nullptr; -} - -Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) { - // Create a new string expression. - std::string StrEncoding; - Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding); - Expr *Replacement = getStringLiteral(StrEncoding); - ReplaceStmt(Exp, Replacement); - - // Replace this subexpr in the parent. - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return Replacement; -} - -Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) { - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl"); - // Create a call to sel_registerName("selName"). - SmallVector<Expr*, 8> SelExprs; - SelExprs.push_back(getStringLiteral(Exp->getSelector().getAsString())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size()); - ReplaceStmt(Exp, SelExp); - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return SelExp; -} - -CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl( - FunctionDecl *FD, Expr **args, unsigned nargs, SourceLocation StartLoc, - SourceLocation EndLoc) { - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = FD->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, msgSendType, - VK_LValue, SourceLocation()); - - // Now, we cast the reference to a pointer to the objc_msgSend type. - QualType pToFunc = Context->getPointerType(msgSendType); - ImplicitCastExpr *ICE = - ImplicitCastExpr::Create(*Context, pToFunc, CK_FunctionToPointerDecay, - DRE, nullptr, VK_RValue); - - const FunctionType *FT = msgSendType->getAs<FunctionType>(); - - CallExpr *Exp = - new (Context) CallExpr(*Context, ICE, llvm::makeArrayRef(args, nargs), - FT->getCallResultType(*Context), - VK_RValue, EndLoc); - return Exp; -} - -static bool scanForProtocolRefs(const char *startBuf, const char *endBuf, - const char *&startRef, const char *&endRef) { - while (startBuf < endBuf) { - if (*startBuf == '<') - startRef = startBuf; // mark the start. - if (*startBuf == '>') { - if (startRef && *startRef == '<') { - endRef = startBuf; // mark the end. - return true; - } - return false; - } - startBuf++; - } - return false; -} - -static void scanToNextArgument(const char *&argRef) { - int angle = 0; - while (*argRef != ')' && (*argRef != ',' || angle > 0)) { - if (*argRef == '<') - angle++; - else if (*argRef == '>') - angle--; - argRef++; - } - assert(angle == 0 && "scanToNextArgument - bad protocol type syntax"); -} - -bool RewriteObjC::needToScanForQualifiers(QualType T) { - if (T->isObjCQualifiedIdType()) - return true; - if (const PointerType *PT = T->getAs<PointerType>()) { - if (PT->getPointeeType()->isObjCQualifiedIdType()) - return true; - } - if (T->isObjCObjectPointerType()) { - T = T->getPointeeType(); - return T->isObjCQualifiedInterfaceType(); - } - if (T->isArrayType()) { - QualType ElemTy = Context->getBaseElementType(T); - return needToScanForQualifiers(ElemTy); - } - return false; -} - -void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) { - QualType Type = E->getType(); - if (needToScanForQualifiers(Type)) { - SourceLocation Loc, EndLoc; - - if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) { - Loc = ECE->getLParenLoc(); - EndLoc = ECE->getRParenLoc(); - } else { - Loc = E->getLocStart(); - EndLoc = E->getLocEnd(); - } - // This will defend against trying to rewrite synthesized expressions. - if (Loc.isInvalid() || EndLoc.isInvalid()) - return; - - const char *startBuf = SM->getCharacterData(Loc); - const char *endBuf = SM->getCharacterData(EndLoc); - const char *startRef = nullptr, *endRef = nullptr; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = Loc.getLocWithOffset(startRef-startBuf); - SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-startBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*"); - InsertText(GreaterLoc, "*/"); - } - } -} - -void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { - SourceLocation Loc; - QualType Type; - const FunctionProtoType *proto = nullptr; - if (VarDecl *VD = dyn_cast<VarDecl>(Dcl)) { - Loc = VD->getLocation(); - Type = VD->getType(); - } - else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Dcl)) { - Loc = FD->getLocation(); - // Check for ObjC 'id' and class types that have been adorned with protocol - // information (id<p>, C<p>*). The protocol references need to be rewritten! - const FunctionType *funcType = FD->getType()->getAs<FunctionType>(); - assert(funcType && "missing function type"); - proto = dyn_cast<FunctionProtoType>(funcType); - if (!proto) - return; - Type = proto->getReturnType(); - } - else if (FieldDecl *FD = dyn_cast<FieldDecl>(Dcl)) { - Loc = FD->getLocation(); - Type = FD->getType(); - } - else - return; - - if (needToScanForQualifiers(Type)) { - // Since types are unique, we need to scan the buffer. - - const char *endBuf = SM->getCharacterData(Loc); - const char *startBuf = endBuf; - while (*startBuf != ';' && *startBuf != '<' && startBuf != MainFileStart) - startBuf--; // scan backward (from the decl location) for return type. - const char *startRef = nullptr, *endRef = nullptr; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = Loc.getLocWithOffset(startRef-endBuf); - SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-endBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*"); - InsertText(GreaterLoc, "*/"); - } - } - if (!proto) - return; // most likely, was a variable - // Now check arguments. - const char *startBuf = SM->getCharacterData(Loc); - const char *startFuncBuf = startBuf; - for (unsigned i = 0; i < proto->getNumParams(); i++) { - if (needToScanForQualifiers(proto->getParamType(i))) { - // Since types are unique, we need to scan the buffer. - - const char *endBuf = startBuf; - // scan forward (from the decl location) for argument types. - scanToNextArgument(endBuf); - const char *startRef = nullptr, *endRef = nullptr; - if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { - // Get the locations of the startRef, endRef. - SourceLocation LessLoc = - Loc.getLocWithOffset(startRef-startFuncBuf); - SourceLocation GreaterLoc = - Loc.getLocWithOffset(endRef-startFuncBuf+1); - // Comment out the protocol references. - InsertText(LessLoc, "/*"); - InsertText(GreaterLoc, "*/"); - } - startBuf = ++endBuf; - } - else { - // If the function name is derived from a macro expansion, then the - // argument buffer will not follow the name. Need to speak with Chris. - while (*startBuf && *startBuf != ')' && *startBuf != ',') - startBuf++; // scan forward (from the decl location) for argument types. - startBuf++; - } - } -} - -void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) { - QualType QT = ND->getType(); - const Type* TypePtr = QT->getAs<Type>(); - if (!isa<TypeOfExprType>(TypePtr)) - return; - while (isa<TypeOfExprType>(TypePtr)) { - const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr); - QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); - TypePtr = QT->getAs<Type>(); - } - // FIXME. This will not work for multiple declarators; as in: - // __typeof__(a) b,c,d; - std::string TypeAsString(QT.getAsString(Context->getPrintingPolicy())); - SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); - const char *startBuf = SM->getCharacterData(DeclLoc); - if (ND->getInit()) { - std::string Name(ND->getNameAsString()); - TypeAsString += " " + Name + " = "; - Expr *E = ND->getInit(); - SourceLocation startLoc; - if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) - startLoc = ECE->getLParenLoc(); - else - startLoc = E->getLocStart(); - startLoc = SM->getExpansionLoc(startLoc); - const char *endBuf = SM->getCharacterData(startLoc); - ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); - } - else { - SourceLocation X = ND->getLocEnd(); - X = SM->getExpansionLoc(X); - const char *endBuf = SM->getCharacterData(X); - ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); - } -} - -// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str); -void RewriteObjC::SynthSelGetUidFunctionDecl() { - IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName"); - SmallVector<QualType, 16> ArgTys; - ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); - QualType getFuncType = - getSimpleFunctionType(Context->getObjCSelType(), ArgTys); - SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - SelGetUidIdent, getFuncType, - nullptr, SC_Extern); -} - -void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) { - // declared in <objc/objc.h> - if (FD->getIdentifier() && - FD->getName() == "sel_registerName") { - SelGetUidFunctionDecl = FD; - return; - } - RewriteObjCQualifiedInterfaceTypes(FD); -} - -void RewriteObjC::RewriteBlockPointerType(std::string& Str, QualType Type) { - std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); - const char *argPtr = TypeString.c_str(); - if (!strchr(argPtr, '^')) { - Str += TypeString; - return; - } - while (*argPtr) { - Str += (*argPtr == '^' ? '*' : *argPtr); - argPtr++; - } -} - -// FIXME. Consolidate this routine with RewriteBlockPointerType. -void RewriteObjC::RewriteBlockPointerTypeVariable(std::string& Str, - ValueDecl *VD) { - QualType Type = VD->getType(); - std::string TypeString(Type.getAsString(Context->getPrintingPolicy())); - const char *argPtr = TypeString.c_str(); - int paren = 0; - while (*argPtr) { - switch (*argPtr) { - case '(': - Str += *argPtr; - paren++; - break; - case ')': - Str += *argPtr; - paren--; - break; - case '^': - Str += '*'; - if (paren == 1) - Str += VD->getNameAsString(); - break; - default: - Str += *argPtr; - break; - } - argPtr++; - } -} - - -void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) { - SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); - const FunctionType *funcType = FD->getType()->getAs<FunctionType>(); - const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(funcType); - if (!proto) - return; - QualType Type = proto->getReturnType(); - std::string FdStr = Type.getAsString(Context->getPrintingPolicy()); - FdStr += " "; - FdStr += FD->getName(); - FdStr += "("; - unsigned numArgs = proto->getNumParams(); - for (unsigned i = 0; i < numArgs; i++) { - QualType ArgType = proto->getParamType(i); - RewriteBlockPointerType(FdStr, ArgType); - if (i+1 < numArgs) - FdStr += ", "; - } - FdStr += ");\n"; - InsertText(FunLocStart, FdStr); - CurFunctionDeclToDeclareForBlock = nullptr; -} - -// SynthSuperConstructorFunctionDecl - id objc_super(id obj, id super); -void RewriteObjC::SynthSuperConstructorFunctionDecl() { - if (SuperConstructorFunctionDecl) - return; - IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super"); - SmallVector<QualType, 16> ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - ArgTys); - SuperConstructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, - nullptr, SC_Extern); -} - -// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...); -void RewriteObjC::SynthMsgSendFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend"); - SmallVector<QualType, 16> ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - ArgTys, /*isVariadic=*/true); - MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, - nullptr, SC_Extern); -} - -// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...); -void RewriteObjC::SynthMsgSendSuperFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper"); - SmallVector<QualType, 16> ArgTys; - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("objc_super")); - QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); - assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - ArgTys, /*isVariadic=*/true); - MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, - nullptr, SC_Extern); -} - -// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...); -void RewriteObjC::SynthMsgSendStretFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret"); - SmallVector<QualType, 16> ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - ArgTys, /*isVariadic=*/true); - MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, - nullptr, SC_Extern); -} - -// SynthMsgSendSuperStretFunctionDecl - -// id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...); -void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { - IdentifierInfo *msgSendIdent = - &Context->Idents.get("objc_msgSendSuper_stret"); - SmallVector<QualType, 16> ArgTys; - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("objc_super")); - QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); - assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - ArgTys, /*isVariadic=*/true); - MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, - msgSendType, nullptr, - SC_Extern); -} - -// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...); -void RewriteObjC::SynthMsgSendFpretFunctionDecl() { - IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret"); - SmallVector<QualType, 16> ArgTys; - QualType argT = Context->getObjCIdType(); - assert(!argT.isNull() && "Can't find 'id' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); - QualType msgSendType = getSimpleFunctionType(Context->DoubleTy, - ArgTys, /*isVariadic=*/true); - MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - msgSendIdent, msgSendType, - nullptr, SC_Extern); -} - -// SynthGetClassFunctionDecl - id objc_getClass(const char *name); -void RewriteObjC::SynthGetClassFunctionDecl() { - IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass"); - SmallVector<QualType, 16> ArgTys; - ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); - QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(), - ArgTys); - GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - getClassIdent, getClassType, - nullptr, SC_Extern); -} - -// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls); -void RewriteObjC::SynthGetSuperClassFunctionDecl() { - IdentifierInfo *getSuperClassIdent = - &Context->Idents.get("class_getSuperclass"); - SmallVector<QualType, 16> ArgTys; - ArgTys.push_back(Context->getObjCClassType()); - QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(), - ArgTys); - GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - getSuperClassIdent, - getClassType, nullptr, - SC_Extern); -} - -// SynthGetMetaClassFunctionDecl - id objc_getMetaClass(const char *name); -void RewriteObjC::SynthGetMetaClassFunctionDecl() { - IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass"); - SmallVector<QualType, 16> ArgTys; - ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); - QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(), - ArgTys); - GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - SourceLocation(), - getClassIdent, getClassType, - nullptr, SC_Extern); -} - -Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { - assert(Exp != nullptr && "Expected non-null ObjCStringLiteral"); - QualType strType = getConstantStringStructType(); - - std::string S = "__NSConstantStringImpl_"; - - std::string tmpName = InFileName; - unsigned i; - for (i=0; i < tmpName.length(); i++) { - char c = tmpName.at(i); - // replace any non-alphanumeric characters with '_'. - if (!isAlphanumeric(c)) - tmpName[i] = '_'; - } - S += tmpName; - S += "_"; - S += utostr(NumObjCStringLiterals++); - - Preamble += "static __NSConstantStringImpl " + S; - Preamble += " __attribute__ ((section (\"__DATA, __cfstring\"))) = {__CFConstantStringClassReference,"; - Preamble += "0x000007c8,"; // utf8_str - // The pretty printer for StringLiteral handles escape characters properly. - std::string prettyBufS; - llvm::raw_string_ostream prettyBuf(prettyBufS); - Exp->getString()->printPretty(prettyBuf, nullptr, PrintingPolicy(LangOpts)); - Preamble += prettyBuf.str(); - Preamble += ","; - Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; - - VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), &Context->Idents.get(S), - strType, nullptr, SC_Static); - DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue, - SourceLocation()); - Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, - Context->getPointerType(DRE->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - // cast to NSConstantString * - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), - CK_CPointerToObjCPointerCast, Unop); - ReplaceStmt(Exp, cast); - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return cast; -} - -// struct objc_super { struct objc_object *receiver; struct objc_class *super; }; -QualType RewriteObjC::getSuperStructType() { - if (!SuperStructDecl) { - SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("objc_super")); - QualType FieldTypes[2]; - - // struct objc_object *receiver; - FieldTypes[0] = Context->getObjCIdType(); - // struct objc_class *super; - FieldTypes[1] = Context->getObjCClassType(); - - // Create fields - for (unsigned i = 0; i < 2; ++i) { - SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl, - SourceLocation(), - SourceLocation(), nullptr, - FieldTypes[i], nullptr, - /*BitWidth=*/nullptr, - /*Mutable=*/false, - ICIS_NoInit)); - } - - SuperStructDecl->completeDefinition(); - } - return Context->getTagDeclType(SuperStructDecl); -} - -QualType RewriteObjC::getConstantStringStructType() { - if (!ConstantStringDecl) { - ConstantStringDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("__NSConstantStringImpl")); - QualType FieldTypes[4]; - - // struct objc_object *receiver; - FieldTypes[0] = Context->getObjCIdType(); - // int flags; - FieldTypes[1] = Context->IntTy; - // char *str; - FieldTypes[2] = Context->getPointerType(Context->CharTy); - // long length; - FieldTypes[3] = Context->LongTy; - - // Create fields - for (unsigned i = 0; i < 4; ++i) { - ConstantStringDecl->addDecl(FieldDecl::Create(*Context, - ConstantStringDecl, - SourceLocation(), - SourceLocation(), nullptr, - FieldTypes[i], nullptr, - /*BitWidth=*/nullptr, - /*Mutable=*/true, - ICIS_NoInit)); - } - - ConstantStringDecl->completeDefinition(); - } - return Context->getTagDeclType(ConstantStringDecl); -} - -CallExpr *RewriteObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavor, - QualType msgSendType, - QualType returnType, - SmallVectorImpl<QualType> &ArgTypes, - SmallVectorImpl<Expr*> &MsgExprs, - ObjCMethodDecl *Method) { - // Create a reference to the objc_msgSend_stret() declaration. - DeclRefExpr *STDRE = new (Context) DeclRefExpr(MsgSendStretFlavor, - false, msgSendType, - VK_LValue, SourceLocation()); - // Need to cast objc_msgSend_stret to "void *" (see above comment). - CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->VoidTy), - CK_BitCast, STDRE); - // Now do the "normal" pointer to function cast. - QualType castType = getSimpleFunctionType(returnType, ArgTypes, - Method ? Method->isVariadic() - : false); - castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, - cast); - - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast); - - const FunctionType *FT = msgSendType->getAs<FunctionType>(); - CallExpr *STCE = new (Context) CallExpr( - *Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, SourceLocation()); - return STCE; - -} - - -Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, - SourceLocation StartLoc, - SourceLocation EndLoc) { - if (!SelGetUidFunctionDecl) - SynthSelGetUidFunctionDecl(); - if (!MsgSendFunctionDecl) - SynthMsgSendFunctionDecl(); - if (!MsgSendSuperFunctionDecl) - SynthMsgSendSuperFunctionDecl(); - if (!MsgSendStretFunctionDecl) - SynthMsgSendStretFunctionDecl(); - if (!MsgSendSuperStretFunctionDecl) - SynthMsgSendSuperStretFunctionDecl(); - if (!MsgSendFpretFunctionDecl) - SynthMsgSendFpretFunctionDecl(); - if (!GetClassFunctionDecl) - SynthGetClassFunctionDecl(); - if (!GetSuperClassFunctionDecl) - SynthGetSuperClassFunctionDecl(); - if (!GetMetaClassFunctionDecl) - SynthGetMetaClassFunctionDecl(); - - // default to objc_msgSend(). - FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; - // May need to use objc_msgSend_stret() as well. - FunctionDecl *MsgSendStretFlavor = nullptr; - if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) { - QualType resultType = mDecl->getReturnType(); - if (resultType->isRecordType()) - MsgSendStretFlavor = MsgSendStretFunctionDecl; - else if (resultType->isRealFloatingType()) - MsgSendFlavor = MsgSendFpretFunctionDecl; - } - - // Synthesize a call to objc_msgSend(). - SmallVector<Expr*, 8> MsgExprs; - switch (Exp->getReceiverKind()) { - case ObjCMessageExpr::SuperClass: { - MsgSendFlavor = MsgSendSuperFunctionDecl; - if (MsgSendStretFlavor) - MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; - assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - - ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); - - SmallVector<Expr*, 4> InitExprs; - - // set the receiver to self, the first argument to all methods. - InitExprs.push_back( - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, - new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), - false, - Context->getObjCIdType(), - VK_RValue, - SourceLocation())) - ); // set the 'receiver'. - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - SmallVector<Expr*, 8> ClsExprs; - ClsExprs.push_back(getStringLiteral(ClassDecl->getIdentifier()->getName())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, - EndLoc); - // (Class)objc_getClass("CurrentClass") - CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, - Context->getObjCClassType(), - CK_BitCast, Cls); - ClsExprs.clear(); - ClsExprs.push_back(ArgExpr); - Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, - &ClsExprs[0], ClsExprs.size(), - StartLoc, EndLoc); - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - // To turn off a warning, type-cast to 'id' - InitExprs.push_back( // set 'super class', using class_getSuperclass(). - NoTypeInfoCStyleCastExpr(Context, - Context->getObjCIdType(), - CK_BitCast, Cls)); - // struct objc_super - QualType superType = getSuperStructType(); - Expr *SuperRep; - - if (LangOpts.MicrosoftExt) { - SynthSuperConstructorFunctionDecl(); - // Simulate a constructor call... - DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperConstructorFunctionDecl, - false, superType, VK_LValue, - SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs, - superType, VK_LValue, - SourceLocation()); - // The code for super is a little tricky to prevent collision with - // the structure definition in the header. The rewriter has it's own - // internal definition (__rw_objc_super) that is uses. This is why - // we need the cast below. For example: - // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) - // - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, - Context->getPointerType(SuperRep->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - SuperRep = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(superType), - CK_BitCast, SuperRep); - } else { - // (struct objc_super) { <exprs from above> } - InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, - SourceLocation()); - TypeSourceInfo *superTInfo - = Context->getTrivialTypeSourceInfo(superType); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, - superType, VK_LValue, - ILE, false); - // struct objc_super * - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, - Context->getPointerType(SuperRep->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - } - MsgExprs.push_back(SuperRep); - break; - } - - case ObjCMessageExpr::Class: { - SmallVector<Expr*, 8> ClsExprs; - ObjCInterfaceDecl *Class - = Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface(); - IdentifierInfo *clsName = Class->getIdentifier(); - ClsExprs.push_back(getStringLiteral(clsName->getName())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(Cls); - break; - } - - case ObjCMessageExpr::SuperInstance:{ - MsgSendFlavor = MsgSendSuperFunctionDecl; - if (MsgSendStretFlavor) - MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; - assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); - SmallVector<Expr*, 4> InitExprs; - - InitExprs.push_back( - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, - new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), - false, - Context->getObjCIdType(), - VK_RValue, SourceLocation())) - ); // set the 'receiver'. - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - SmallVector<Expr*, 8> ClsExprs; - ClsExprs.push_back(getStringLiteral(ClassDecl->getIdentifier()->getName())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - // (Class)objc_getClass("CurrentClass") - CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, - Context->getObjCClassType(), - CK_BitCast, Cls); - ClsExprs.clear(); - ClsExprs.push_back(ArgExpr); - Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, - &ClsExprs[0], ClsExprs.size(), - StartLoc, EndLoc); - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - // To turn off a warning, type-cast to 'id' - InitExprs.push_back( - // set 'super class', using class_getSuperclass(). - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, Cls)); - // struct objc_super - QualType superType = getSuperStructType(); - Expr *SuperRep; - - if (LangOpts.MicrosoftExt) { - SynthSuperConstructorFunctionDecl(); - // Simulate a constructor call... - DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperConstructorFunctionDecl, - false, superType, VK_LValue, - SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs, - superType, VK_LValue, SourceLocation()); - // The code for super is a little tricky to prevent collision with - // the structure definition in the header. The rewriter has it's own - // internal definition (__rw_objc_super) that is uses. This is why - // we need the cast below. For example: - // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) - // - SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, - Context->getPointerType(SuperRep->getType()), - VK_RValue, OK_Ordinary, - SourceLocation()); - SuperRep = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(superType), - CK_BitCast, SuperRep); - } else { - // (struct objc_super) { <exprs from above> } - InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, - SourceLocation()); - TypeSourceInfo *superTInfo - = Context->getTrivialTypeSourceInfo(superType); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, - superType, VK_RValue, ILE, - false); - } - MsgExprs.push_back(SuperRep); - break; - } - - case ObjCMessageExpr::Instance: { - // Remove all type-casts because it may contain objc-style types; e.g. - // Foo<Proto> *. - Expr *recExpr = Exp->getInstanceReceiver(); - while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr)) - recExpr = CE->getSubExpr(); - CastKind CK = recExpr->getType()->isObjCObjectPointerType() - ? CK_BitCast : recExpr->getType()->isBlockPointerType() - ? CK_BlockPointerToObjCPointerCast - : CK_CPointerToObjCPointerCast; - - recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK, recExpr); - MsgExprs.push_back(recExpr); - break; - } - } - - // Create a call to sel_registerName("selName"), it will be the 2nd argument. - SmallVector<Expr*, 8> SelExprs; - SelExprs.push_back(getStringLiteral(Exp->getSelector().getAsString())); - CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size(), - StartLoc, - EndLoc); - MsgExprs.push_back(SelExp); - - // Now push any user supplied arguments. - for (unsigned i = 0; i < Exp->getNumArgs(); i++) { - Expr *userExpr = Exp->getArg(i); - // Make all implicit casts explicit...ICE comes in handy:-) - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) { - // Reuse the ICE type, it is exactly what the doctor ordered. - QualType type = ICE->getType(); - if (needToScanForQualifiers(type)) - type = Context->getObjCIdType(); - // Make sure we convert "type (^)(...)" to "type (*)(...)". - (void)convertBlockPointerToFunctionPointer(type); - const Expr *SubExpr = ICE->IgnoreParenImpCasts(); - CastKind CK; - if (SubExpr->getType()->isIntegralType(*Context) && - type->isBooleanType()) { - CK = CK_IntegralToBoolean; - } else if (type->isObjCObjectPointerType()) { - if (SubExpr->getType()->isBlockPointerType()) { - CK = CK_BlockPointerToObjCPointerCast; - } else if (SubExpr->getType()->isPointerType()) { - CK = CK_CPointerToObjCPointerCast; - } else { - CK = CK_BitCast; - } - } else { - CK = CK_BitCast; - } - - userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, userExpr); - } - // Make id<P...> cast into an 'id' cast. - else if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(userExpr)) { - if (CE->getType()->isObjCQualifiedIdType()) { - while ((CE = dyn_cast<CStyleCastExpr>(userExpr))) - userExpr = CE->getSubExpr(); - CastKind CK; - if (userExpr->getType()->isIntegralType(*Context)) { - CK = CK_IntegralToPointer; - } else if (userExpr->getType()->isBlockPointerType()) { - CK = CK_BlockPointerToObjCPointerCast; - } else if (userExpr->getType()->isPointerType()) { - CK = CK_CPointerToObjCPointerCast; - } else { - CK = CK_BitCast; - } - userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK, userExpr); - } - } - MsgExprs.push_back(userExpr); - // We've transferred the ownership to MsgExprs. For now, we *don't* null - // out the argument in the original expression (since we aren't deleting - // the ObjCMessageExpr). See RewritePropertyOrImplicitSetter() usage for more info. - //Exp->setArg(i, 0); - } - // Generate the funky cast. - CastExpr *cast; - SmallVector<QualType, 8> ArgTypes; - QualType returnType; - - // Push 'id' and 'SEL', the 2 implicit arguments. - if (MsgSendFlavor == MsgSendSuperFunctionDecl) - ArgTypes.push_back(Context->getPointerType(getSuperStructType())); - else - ArgTypes.push_back(Context->getObjCIdType()); - ArgTypes.push_back(Context->getObjCSelType()); - if (ObjCMethodDecl *OMD = Exp->getMethodDecl()) { - // Push any user argument types. - for (const auto *PI : OMD->params()) { - QualType t = PI->getType()->isObjCQualifiedIdType() - ? Context->getObjCIdType() - : PI->getType(); - // Make sure we convert "t (^)(...)" to "t (*)(...)". - (void)convertBlockPointerToFunctionPointer(t); - ArgTypes.push_back(t); - } - returnType = Exp->getType(); - convertToUnqualifiedObjCType(returnType); - (void)convertBlockPointerToFunctionPointer(returnType); - } else { - returnType = Context->getObjCIdType(); - } - // Get the type, we will need to reference it in a couple spots. - QualType msgSendType = MsgSendFlavor->getType(); - - // Create a reference to the objc_msgSend() declaration. - DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, - VK_LValue, SourceLocation()); - - // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid). - // If we don't do this cast, we get the following bizarre warning/note: - // xx.m:13: warning: function called through a non-compatible type - // xx.m:13: note: if this code is reached, the program will abort - cast = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(Context->VoidTy), - CK_BitCast, DRE); - - // Now do the "normal" pointer to function cast. - // If we don't have a method decl, force a variadic cast. - const ObjCMethodDecl *MD = Exp->getMethodDecl(); - QualType castType = - getSimpleFunctionType(returnType, ArgTypes, MD ? MD->isVariadic() : true); - castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, - cast); - - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); - - const FunctionType *FT = msgSendType->getAs<FunctionType>(); - CallExpr *CE = new (Context) - CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc); - Stmt *ReplacingStmt = CE; - if (MsgSendStretFlavor) { - // We have the method which returns a struct/union. Must also generate - // call to objc_msgSend_stret and hang both varieties on a conditional - // expression which dictate which one to envoke depending on size of - // method's return type. - - CallExpr *STCE = SynthMsgSendStretCallExpr(MsgSendStretFlavor, - msgSendType, returnType, - ArgTypes, MsgExprs, - Exp->getMethodDecl()); - - // Build sizeof(returnType) - UnaryExprOrTypeTraitExpr *sizeofExpr = - new (Context) UnaryExprOrTypeTraitExpr(UETT_SizeOf, - Context->getTrivialTypeSourceInfo(returnType), - Context->getSizeType(), SourceLocation(), - SourceLocation()); - // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) - // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases. - // For X86 it is more complicated and some kind of target specific routine - // is needed to decide what to do. - unsigned IntSize = - static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); - IntegerLiteral *limit = IntegerLiteral::Create(*Context, - llvm::APInt(IntSize, 8), - Context->IntTy, - SourceLocation()); - BinaryOperator *lessThanExpr = - new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy, - VK_RValue, OK_Ordinary, SourceLocation(), - false); - // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) - ConditionalOperator *CondExpr = - new (Context) ConditionalOperator(lessThanExpr, - SourceLocation(), CE, - SourceLocation(), STCE, - returnType, VK_RValue, OK_Ordinary); - ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - CondExpr); - } - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return ReplacingStmt; -} - -Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { - Stmt *ReplacingStmt = SynthMessageExpr(Exp, Exp->getLocStart(), - Exp->getLocEnd()); - - // Now do the actual rewrite. - ReplaceStmt(Exp, ReplacingStmt); - - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return ReplacingStmt; -} - -// typedef struct objc_object Protocol; -QualType RewriteObjC::getProtocolType() { - if (!ProtocolTypeDecl) { - TypeSourceInfo *TInfo - = Context->getTrivialTypeSourceInfo(Context->getObjCIdType()); - ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("Protocol"), - TInfo); - } - return Context->getTypeDeclType(ProtocolTypeDecl); -} - -/// RewriteObjCProtocolExpr - Rewrite a protocol expression into -/// a synthesized/forward data reference (to the protocol's metadata). -/// The forward references (and metadata) are generated in -/// RewriteObjC::HandleTranslationUnit(). -Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { - std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString(); - IdentifierInfo *ID = &Context->Idents.get(Name); - VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), ID, getProtocolType(), - nullptr, SC_Extern); - DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(), - VK_LValue, SourceLocation()); - Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf, - Context->getPointerType(DRE->getType()), - VK_RValue, OK_Ordinary, SourceLocation()); - CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(), - CK_BitCast, - DerefExpr); - ReplaceStmt(Exp, castExpr); - ProtocolExprDecls.insert(Exp->getProtocol()->getCanonicalDecl()); - // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. - return castExpr; - -} - -bool RewriteObjC::BufferContainsPPDirectives(const char *startBuf, - const char *endBuf) { - while (startBuf < endBuf) { - if (*startBuf == '#') { - // Skip whitespace. - for (++startBuf; startBuf[0] == ' ' || startBuf[0] == '\t'; ++startBuf) - ; - if (!strncmp(startBuf, "if", strlen("if")) || - !strncmp(startBuf, "ifdef", strlen("ifdef")) || - !strncmp(startBuf, "ifndef", strlen("ifndef")) || - !strncmp(startBuf, "define", strlen("define")) || - !strncmp(startBuf, "undef", strlen("undef")) || - !strncmp(startBuf, "else", strlen("else")) || - !strncmp(startBuf, "elif", strlen("elif")) || - !strncmp(startBuf, "endif", strlen("endif")) || - !strncmp(startBuf, "pragma", strlen("pragma")) || - !strncmp(startBuf, "include", strlen("include")) || - !strncmp(startBuf, "import", strlen("import")) || - !strncmp(startBuf, "include_next", strlen("include_next"))) - return true; - } - startBuf++; - } - return false; -} - -/// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to -/// an objective-c class with ivars. -void RewriteObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl, - std::string &Result) { - assert(CDecl && "Class missing in SynthesizeObjCInternalStruct"); - assert(CDecl->getName() != "" && - "Name missing in SynthesizeObjCInternalStruct"); - // Do not synthesize more than once. - if (ObjCSynthesizedStructs.count(CDecl)) - return; - ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass(); - int NumIvars = CDecl->ivar_size(); - SourceLocation LocStart = CDecl->getLocStart(); - SourceLocation LocEnd = CDecl->getEndOfDefinitionLoc(); - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - - // If no ivars and no root or if its root, directly or indirectly, - // have no ivars (thus not synthesized) then no need to synthesize this class. - if ((!CDecl->isThisDeclarationADefinition() || NumIvars == 0) && - (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) { - endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); - ReplaceText(LocStart, endBuf-startBuf, Result); - return; - } - - // FIXME: This has potential of causing problem. If - // SynthesizeObjCInternalStruct is ever called recursively. - Result += "\nstruct "; - Result += CDecl->getNameAsString(); - if (LangOpts.MicrosoftExt) - Result += "_IMPL"; - - if (NumIvars > 0) { - const char *cursor = strchr(startBuf, '{'); - assert((cursor && endBuf) - && "SynthesizeObjCInternalStruct - malformed @interface"); - // If the buffer contains preprocessor directives, we do more fine-grained - // rewrites. This is intended to fix code that looks like (which occurs in - // NSURL.h, for example): - // - // #ifdef XYZ - // @interface Foo : NSObject - // #else - // @interface FooBar : NSObject - // #endif - // { - // int i; - // } - // @end - // - // This clause is segregated to avoid breaking the common case. - if (BufferContainsPPDirectives(startBuf, cursor)) { - SourceLocation L = RCDecl ? CDecl->getSuperClassLoc() : - CDecl->getAtStartLoc(); - const char *endHeader = SM->getCharacterData(L); - endHeader += Lexer::MeasureTokenLength(L, *SM, LangOpts); - - if (CDecl->protocol_begin() != CDecl->protocol_end()) { - // advance to the end of the referenced protocols. - while (endHeader < cursor && *endHeader != '>') endHeader++; - endHeader++; - } - // rewrite the original header - ReplaceText(LocStart, endHeader-startBuf, Result); - } else { - // rewrite the original header *without* disturbing the '{' - ReplaceText(LocStart, cursor-startBuf, Result); - } - if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) { - Result = "\n struct "; - Result += RCDecl->getNameAsString(); - Result += "_IMPL "; - Result += RCDecl->getNameAsString(); - Result += "_IVARS;\n"; - - // insert the super class structure definition. - SourceLocation OnePastCurly = - LocStart.getLocWithOffset(cursor-startBuf+1); - InsertText(OnePastCurly, Result); - } - cursor++; // past '{' - - // Now comment out any visibility specifiers. - while (cursor < endBuf) { - if (*cursor == '@') { - SourceLocation atLoc = LocStart.getLocWithOffset(cursor-startBuf); - // Skip whitespace. - for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor) - /*scan*/; - - // FIXME: presence of @public, etc. inside comment results in - // this transformation as well, which is still correct c-code. - if (!strncmp(cursor, "public", strlen("public")) || - !strncmp(cursor, "private", strlen("private")) || - !strncmp(cursor, "package", strlen("package")) || - !strncmp(cursor, "protected", strlen("protected"))) - InsertText(atLoc, "// "); - } - // FIXME: If there are cases where '<' is used in ivar declaration part - // of user code, then scan the ivar list and use needToScanForQualifiers - // for type checking. - else if (*cursor == '<') { - SourceLocation atLoc = LocStart.getLocWithOffset(cursor-startBuf); - InsertText(atLoc, "/* "); - cursor = strchr(cursor, '>'); - cursor++; - atLoc = LocStart.getLocWithOffset(cursor-startBuf); - InsertText(atLoc, " */"); - } else if (*cursor == '^') { // rewrite block specifier. - SourceLocation caretLoc = LocStart.getLocWithOffset(cursor-startBuf); - ReplaceText(caretLoc, 1, "*"); - } - cursor++; - } - // Don't forget to add a ';'!! - InsertText(LocEnd.getLocWithOffset(1), ";"); - } else { // we don't have any instance variables - insert super struct. - endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); - Result += " {\n struct "; - Result += RCDecl->getNameAsString(); - Result += "_IMPL "; - Result += RCDecl->getNameAsString(); - Result += "_IVARS;\n};\n"; - ReplaceText(LocStart, endBuf-startBuf, Result); - } - // Mark this struct as having been generated. - if (!ObjCSynthesizedStructs.insert(CDecl)) - llvm_unreachable("struct already synthesize- SynthesizeObjCInternalStruct"); -} - -//===----------------------------------------------------------------------===// -// Meta Data Emission -//===----------------------------------------------------------------------===// - - -/// RewriteImplementations - This routine rewrites all method implementations -/// and emits meta-data. - -void RewriteObjC::RewriteImplementations() { - int ClsDefCount = ClassImplementation.size(); - int CatDefCount = CategoryImplementation.size(); - - // Rewrite implemented methods - for (int i = 0; i < ClsDefCount; i++) - RewriteImplementationDecl(ClassImplementation[i]); - - for (int i = 0; i < CatDefCount; i++) - RewriteImplementationDecl(CategoryImplementation[i]); -} - -void RewriteObjC::RewriteByRefString(std::string &ResultStr, - const std::string &Name, - ValueDecl *VD, bool def) { - assert(BlockByRefDeclNo.count(VD) && - "RewriteByRefString: ByRef decl missing"); - if (def) - ResultStr += "struct "; - ResultStr += "__Block_byref_" + Name + - "_" + utostr(BlockByRefDeclNo[VD]) ; -} - -static bool HasLocalVariableExternalStorage(ValueDecl *VD) { - if (VarDecl *Var = dyn_cast<VarDecl>(VD)) - return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage()); - return false; -} - -std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, - StringRef funcName, - std::string Tag) { - const FunctionType *AFT = CE->getFunctionType(); - QualType RT = AFT->getReturnType(); - std::string StructRef = "struct " + Tag; - std::string S = "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" + - funcName.str() + "_" + "block_func_" + utostr(i); - - BlockDecl *BD = CE->getBlockDecl(); - - if (isa<FunctionNoProtoType>(AFT)) { - // No user-supplied arguments. Still need to pass in a pointer to the - // block (to reference imported block decl refs). - S += "(" + StructRef + " *__cself)"; - } else if (BD->param_empty()) { - S += "(" + StructRef + " *__cself)"; - } else { - const FunctionProtoType *FT = cast<FunctionProtoType>(AFT); - assert(FT && "SynthesizeBlockFunc: No function proto"); - S += '('; - // first add the implicit argument. - S += StructRef + " *__cself, "; - std::string ParamStr; - for (BlockDecl::param_iterator AI = BD->param_begin(), - E = BD->param_end(); AI != E; ++AI) { - if (AI != BD->param_begin()) S += ", "; - ParamStr = (*AI)->getNameAsString(); - QualType QT = (*AI)->getType(); - (void)convertBlockPointerToFunctionPointer(QT); - QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy()); - S += ParamStr; - } - if (FT->isVariadic()) { - if (!BD->param_empty()) S += ", "; - S += "..."; - } - S += ')'; - } - S += " {\n"; - - // Create local declarations to avoid rewriting all closure decl ref exprs. - // First, emit a declaration for all "by ref" decls. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - S += " "; - std::string Name = (*I)->getNameAsString(); - std::string TypeString; - RewriteByRefString(TypeString, Name, (*I)); - TypeString += " *"; - Name = TypeString + Name; - S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; - } - // Next, emit a declaration for all "by copy" declarations. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - S += " "; - // Handle nested closure invocation. For example: - // - // void (^myImportedClosure)(void); - // myImportedClosure = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherClosure)(void); - // anotherClosure = ^(void) { - // myImportedClosure(); // import and invoke the closure - // }; - // - if (isTopLevelBlockPointerType((*I)->getType())) { - RewriteBlockPointerTypeVariable(S, (*I)); - S += " = ("; - RewriteBlockPointerType(S, (*I)->getType()); - S += ")"; - S += "__cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; - } - else { - std::string Name = (*I)->getNameAsString(); - QualType QT = (*I)->getType(); - if (HasLocalVariableExternalStorage(*I)) - QT = Context->getPointerType(QT); - QT.getAsStringInternal(Name, Context->getPrintingPolicy()); - S += Name + " = __cself->" + - (*I)->getNameAsString() + "; // bound by copy\n"; - } - } - std::string RewrittenStr = RewrittenBlockExprs[CE]; - const char *cstr = RewrittenStr.c_str(); - while (*cstr++ != '{') ; - S += cstr; - S += "\n"; - return S; -} - -std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - StringRef funcName, - std::string Tag) { - std::string StructRef = "struct " + Tag; - std::string S = "static void __"; - - S += funcName; - S += "_block_copy_" + utostr(i); - S += "(" + StructRef; - S += "*dst, " + StructRef; - S += "*src) {"; - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), - E = ImportedBlockDecls.end(); I != E; ++I) { - ValueDecl *VD = (*I); - S += "_Block_object_assign((void*)&dst->"; - S += (*I)->getNameAsString(); - S += ", (void*)src->"; - S += (*I)->getNameAsString(); - if (BlockByRefDeclsPtrSet.count((*I))) - S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; - else if (VD->getType()->isBlockPointerType()) - S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; - else - S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; - } - S += "}\n"; - - S += "\nstatic void __"; - S += funcName; - S += "_block_dispose_" + utostr(i); - S += "(" + StructRef; - S += "*src) {"; - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), - E = ImportedBlockDecls.end(); I != E; ++I) { - ValueDecl *VD = (*I); - S += "_Block_object_dispose((void*)src->"; - S += (*I)->getNameAsString(); - if (BlockByRefDeclsPtrSet.count((*I))) - S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; - else if (VD->getType()->isBlockPointerType()) - S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; - else - S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; - } - S += "}\n"; - return S; -} - -std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - std::string Desc) { - std::string S = "\nstruct " + Tag; - std::string Constructor = " " + Tag; - - S += " {\n struct __block_impl impl;\n"; - S += " struct " + Desc; - S += "* Desc;\n"; - - Constructor += "(void *fp, "; // Invoke function pointer. - Constructor += "struct " + Desc; // Descriptor pointer. - Constructor += " *desc"; - - if (BlockDeclRefs.size()) { - // Output all "by copy" declarations. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - S += " "; - std::string FieldName = (*I)->getNameAsString(); - std::string ArgName = "_" + FieldName; - // Handle nested closure invocation. For example: - // - // void (^myImportedBlock)(void); - // myImportedBlock = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherBlock)(void); - // anotherBlock = ^(void) { - // myImportedBlock(); // import and invoke the closure - // }; - // - if (isTopLevelBlockPointerType((*I)->getType())) { - S += "struct __block_impl *"; - Constructor += ", void *" + ArgName; - } else { - QualType QT = (*I)->getType(); - if (HasLocalVariableExternalStorage(*I)) - QT = Context->getPointerType(QT); - QT.getAsStringInternal(FieldName, Context->getPrintingPolicy()); - QT.getAsStringInternal(ArgName, Context->getPrintingPolicy()); - Constructor += ", " + ArgName; - } - S += FieldName + ";\n"; - } - // Output all "by ref" declarations. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - S += " "; - std::string FieldName = (*I)->getNameAsString(); - std::string ArgName = "_" + FieldName; - { - std::string TypeString; - RewriteByRefString(TypeString, FieldName, (*I)); - TypeString += " *"; - FieldName = TypeString + FieldName; - ArgName = TypeString + ArgName; - Constructor += ", " + ArgName; - } - S += FieldName + "; // by ref\n"; - } - // Finish writing the constructor. - Constructor += ", int flags=0)"; - // Initialize all "by copy" arguments. - bool firsTime = true; - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); - if (firsTime) { - Constructor += " : "; - firsTime = false; - } - else - Constructor += ", "; - if (isTopLevelBlockPointerType((*I)->getType())) - Constructor += Name + "((struct __block_impl *)_" + Name + ")"; - else - Constructor += Name + "(_" + Name + ")"; - } - // Initialize all "by ref" arguments. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); - if (firsTime) { - Constructor += " : "; - firsTime = false; - } - else - Constructor += ", "; - Constructor += Name + "(_" + Name + "->__forwarding)"; - } - - Constructor += " {\n"; - if (GlobalVarDecl) - Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; - else - Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - - Constructor += " Desc = desc;\n"; - } else { - // Finish writing the constructor. - Constructor += ", int flags=0) {\n"; - if (GlobalVarDecl) - Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; - else - Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - Constructor += " Desc = desc;\n"; - } - Constructor += " "; - Constructor += "}\n"; - S += Constructor; - S += "};\n"; - return S; -} - -std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, - std::string ImplTag, int i, - StringRef FunName, - unsigned hasCopy) { - std::string S = "\nstatic struct " + DescTag; - - S += " {\n unsigned long reserved;\n"; - S += " unsigned long Block_size;\n"; - if (hasCopy) { - S += " void (*copy)(struct "; - S += ImplTag; S += "*, struct "; - S += ImplTag; S += "*);\n"; - - S += " void (*dispose)(struct "; - S += ImplTag; S += "*);\n"; - } - S += "} "; - - S += DescTag + "_DATA = { 0, sizeof(struct "; - S += ImplTag + ")"; - if (hasCopy) { - S += ", __" + FunName.str() + "_block_copy_" + utostr(i); - S += ", __" + FunName.str() + "_block_dispose_" + utostr(i); - } - S += "};\n"; - return S; -} - -void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, - StringRef FunName) { - // Insert declaration for the function in which block literal is used. - if (CurFunctionDeclToDeclareForBlock && !Blocks.empty()) - RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); - bool RewriteSC = (GlobalVarDecl && - !Blocks.empty() && - GlobalVarDecl->getStorageClass() == SC_Static && - GlobalVarDecl->getType().getCVRQualifiers()); - if (RewriteSC) { - std::string SC(" void __"); - SC += GlobalVarDecl->getNameAsString(); - SC += "() {}"; - InsertText(FunLocStart, SC); - } - - // Insert closures that were part of the function. - for (unsigned i = 0, count=0; i < Blocks.size(); i++) { - CollectBlockDeclRefInfo(Blocks[i]); - // Need to copy-in the inner copied-in variables not actually used in this - // block. - for (int j = 0; j < InnerDeclRefsCount[i]; j++) { - DeclRefExpr *Exp = InnerDeclRefs[count++]; - ValueDecl *VD = Exp->getDecl(); - BlockDeclRefs.push_back(Exp); - if (!VD->hasAttr<BlocksAttr>() && !BlockByCopyDeclsPtrSet.count(VD)) { - BlockByCopyDeclsPtrSet.insert(VD); - BlockByCopyDecls.push_back(VD); - } - if (VD->hasAttr<BlocksAttr>() && !BlockByRefDeclsPtrSet.count(VD)) { - BlockByRefDeclsPtrSet.insert(VD); - BlockByRefDecls.push_back(VD); - } - // imported objects in the inner blocks not used in the outer - // blocks must be copied/disposed in the outer block as well. - if (VD->hasAttr<BlocksAttr>() || - VD->getType()->isObjCObjectPointerType() || - VD->getType()->isBlockPointerType()) - ImportedBlockDecls.insert(VD); - } - - std::string ImplTag = "__" + FunName.str() + "_block_impl_" + utostr(i); - std::string DescTag = "__" + FunName.str() + "_block_desc_" + utostr(i); - - std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag); - - InsertText(FunLocStart, CI); - - std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag); - - InsertText(FunLocStart, CF); - - if (ImportedBlockDecls.size()) { - std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag); - InsertText(FunLocStart, HF); - } - std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName, - ImportedBlockDecls.size() > 0); - InsertText(FunLocStart, BD); - - BlockDeclRefs.clear(); - BlockByRefDecls.clear(); - BlockByRefDeclsPtrSet.clear(); - BlockByCopyDecls.clear(); - BlockByCopyDeclsPtrSet.clear(); - ImportedBlockDecls.clear(); - } - if (RewriteSC) { - // Must insert any 'const/volatile/static here. Since it has been - // removed as result of rewriting of block literals. - std::string SC; - if (GlobalVarDecl->getStorageClass() == SC_Static) - SC = "static "; - if (GlobalVarDecl->getType().isConstQualified()) - SC += "const "; - if (GlobalVarDecl->getType().isVolatileQualified()) - SC += "volatile "; - if (GlobalVarDecl->getType().isRestrictQualified()) - SC += "restrict "; - InsertText(FunLocStart, SC); - } - - Blocks.clear(); - InnerDeclRefsCount.clear(); - InnerDeclRefs.clear(); - RewrittenBlockExprs.clear(); -} - -void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { - SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); - StringRef FuncName = FD->getName(); - - SynthesizeBlockLiterals(FunLocStart, FuncName); -} - -static void BuildUniqueMethodName(std::string &Name, - ObjCMethodDecl *MD) { - ObjCInterfaceDecl *IFace = MD->getClassInterface(); - Name = IFace->getName(); - Name += "__" + MD->getSelector().getAsString(); - // Convert colons to underscores. - std::string::size_type loc = 0; - while ((loc = Name.find(":", loc)) != std::string::npos) - Name.replace(loc, 1, "_"); -} - -void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) { - //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n"); - //SourceLocation FunLocStart = MD->getLocStart(); - SourceLocation FunLocStart = MD->getLocStart(); - std::string FuncName; - BuildUniqueMethodName(FuncName, MD); - SynthesizeBlockLiterals(FunLocStart, FuncName); -} - -void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) { - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) - GetBlockDeclRefExprs(CBE->getBody()); - else - GetBlockDeclRefExprs(*CI); - } - // Handle specific things. - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) { - if (DRE->refersToEnclosingLocal()) { - // FIXME: Handle enums. - if (!isa<FunctionDecl>(DRE->getDecl())) - BlockDeclRefs.push_back(DRE); - if (HasLocalVariableExternalStorage(DRE->getDecl())) - BlockDeclRefs.push_back(DRE); - } - } - - return; -} - -void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S, - SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs, - llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts) { - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) { - InnerContexts.insert(cast<DeclContext>(CBE->getBlockDecl())); - GetInnerBlockDeclRefExprs(CBE->getBody(), - InnerBlockDeclRefs, - InnerContexts); - } - else - GetInnerBlockDeclRefExprs(*CI, - InnerBlockDeclRefs, - InnerContexts); - - } - // Handle specific things. - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) { - if (DRE->refersToEnclosingLocal()) { - if (!isa<FunctionDecl>(DRE->getDecl()) && - !InnerContexts.count(DRE->getDecl()->getDeclContext())) - InnerBlockDeclRefs.push_back(DRE); - if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) - if (Var->isFunctionOrMethodVarDecl()) - ImportedLocalExternalDecls.insert(Var); - } - } - - return; -} - -/// convertFunctionTypeOfBlocks - This routine converts a function type -/// whose result type may be a block pointer or whose argument type(s) -/// might be block pointers to an equivalent function type replacing -/// all block pointers to function pointers. -QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) { - const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT); - // FTP will be null for closures that don't take arguments. - // Generate a funky cast. - SmallVector<QualType, 8> ArgTypes; - QualType Res = FT->getReturnType(); - bool HasBlockType = convertBlockPointerToFunctionPointer(Res); - - if (FTP) { - for (auto &I : FTP->param_types()) { - QualType t = I; - // Make sure we convert "t (^)(...)" to "t (*)(...)". - if (convertBlockPointerToFunctionPointer(t)) - HasBlockType = true; - ArgTypes.push_back(t); - } - } - QualType FuncType; - // FIXME. Does this work if block takes no argument but has a return type - // which is of block type? - if (HasBlockType) - FuncType = getSimpleFunctionType(Res, ArgTypes); - else FuncType = QualType(FT, 0); - return FuncType; -} - -Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { - // Navigate to relevant type information. - const BlockPointerType *CPT = nullptr; - - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BlockExp)) { - CPT = DRE->getType()->getAs<BlockPointerType>(); - } else if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(BlockExp)) { - CPT = MExpr->getType()->getAs<BlockPointerType>(); - } - else if (const ParenExpr *PRE = dyn_cast<ParenExpr>(BlockExp)) { - return SynthesizeBlockCall(Exp, PRE->getSubExpr()); - } - else if (const ImplicitCastExpr *IEXPR = dyn_cast<ImplicitCastExpr>(BlockExp)) - CPT = IEXPR->getType()->getAs<BlockPointerType>(); - else if (const ConditionalOperator *CEXPR = - dyn_cast<ConditionalOperator>(BlockExp)) { - Expr *LHSExp = CEXPR->getLHS(); - Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp); - Expr *RHSExp = CEXPR->getRHS(); - Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp); - Expr *CONDExp = CEXPR->getCond(); - ConditionalOperator *CondExpr = - new (Context) ConditionalOperator(CONDExp, - SourceLocation(), cast<Expr>(LHSStmt), - SourceLocation(), cast<Expr>(RHSStmt), - Exp->getType(), VK_RValue, OK_Ordinary); - return CondExpr; - } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) { - CPT = IRE->getType()->getAs<BlockPointerType>(); - } else if (const PseudoObjectExpr *POE - = dyn_cast<PseudoObjectExpr>(BlockExp)) { - CPT = POE->getType()->castAs<BlockPointerType>(); - } else { - assert(1 && "RewriteBlockClass: Bad type"); - } - assert(CPT && "RewriteBlockClass: Bad type"); - const FunctionType *FT = CPT->getPointeeType()->getAs<FunctionType>(); - assert(FT && "RewriteBlockClass: Bad type"); - const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT); - // FTP will be null for closures that don't take arguments. - - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("__block_impl")); - QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD)); - - // Generate a funky cast. - SmallVector<QualType, 8> ArgTypes; - - // Push the block argument type. - ArgTypes.push_back(PtrBlock); - if (FTP) { - for (auto &I : FTP->param_types()) { - QualType t = I; - // Make sure we convert "t (^)(...)" to "t (*)(...)". - if (!convertBlockPointerToFunctionPointer(t)) - convertToUnqualifiedObjCType(t); - ArgTypes.push_back(t); - } - } - // Now do the pointer to function cast. - QualType PtrToFuncCastType = getSimpleFunctionType(Exp->getType(), ArgTypes); - - PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType); - - CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock, - CK_BitCast, - const_cast<Expr*>(BlockExp)); - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - BlkCast); - //PE->dump(); - - FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), - SourceLocation(), - &Context->Idents.get("FuncPtr"), - Context->VoidPtrTy, nullptr, - /*BitWidth=*/nullptr, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), - FD->getType(), VK_LValue, - OK_Ordinary); - - - CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType, - CK_BitCast, ME); - PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast); - - SmallVector<Expr*, 8> BlkExprs; - // Add the implicit argument. - BlkExprs.push_back(BlkCast); - // Add the user arguments. - for (CallExpr::arg_iterator I = Exp->arg_begin(), - E = Exp->arg_end(); I != E; ++I) { - BlkExprs.push_back(*I); - } - CallExpr *CE = new (Context) CallExpr(*Context, PE, BlkExprs, - Exp->getType(), VK_RValue, - SourceLocation()); - return CE; -} - -// We need to return the rewritten expression to handle cases where the -// BlockDeclRefExpr is embedded in another expression being rewritten. -// For example: -// -// int main() { -// __block Foo *f; -// __block int i; -// -// void (^myblock)() = ^() { -// [f test]; // f is a BlockDeclRefExpr embedded in a message (which is being rewritten). -// i = 77; -// }; -//} -Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { - // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR - // for each DeclRefExp where BYREFVAR is name of the variable. - ValueDecl *VD = DeclRefExp->getDecl(); - bool isArrow = DeclRefExp->refersToEnclosingLocal(); - - FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), - SourceLocation(), - &Context->Idents.get("__forwarding"), - Context->VoidPtrTy, nullptr, - /*BitWidth=*/nullptr, /*Mutable=*/true, - ICIS_NoInit); - MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, - FD, SourceLocation(), - FD->getType(), VK_LValue, - OK_Ordinary); - - StringRef Name = VD->getName(); - FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(), - &Context->Idents.get(Name), - Context->VoidPtrTy, nullptr, - /*BitWidth=*/nullptr, /*Mutable=*/true, - ICIS_NoInit); - ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), - DeclRefExp->getType(), VK_LValue, OK_Ordinary); - - - - // Need parens to enforce precedence. - ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(), - DeclRefExp->getExprLoc(), - ME); - ReplaceStmt(DeclRefExp, PE); - return PE; -} - -// Rewrites the imported local variable V with external storage -// (static, extern, etc.) as *V -// -Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) { - ValueDecl *VD = DRE->getDecl(); - if (VarDecl *Var = dyn_cast<VarDecl>(VD)) - if (!ImportedLocalExternalDecls.count(Var)) - return DRE; - Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(), - VK_LValue, OK_Ordinary, - DRE->getLocation()); - // Need parens to enforce precedence. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), - Exp); - ReplaceStmt(DRE, PE); - return PE; -} - -void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) { - SourceLocation LocStart = CE->getLParenLoc(); - SourceLocation LocEnd = CE->getRParenLoc(); - - // Need to avoid trying to rewrite synthesized casts. - if (LocStart.isInvalid()) - return; - // Need to avoid trying to rewrite casts contained in macros. - if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd)) - return; - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - QualType QT = CE->getType(); - const Type* TypePtr = QT->getAs<Type>(); - if (isa<TypeOfExprType>(TypePtr)) { - const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr); - QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); - std::string TypeAsString = "("; - RewriteBlockPointerType(TypeAsString, QT); - TypeAsString += ")"; - ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString); - return; - } - // advance the location to startArgList. - const char *argPtr = startBuf; - - while (*argPtr++ && (argPtr < endBuf)) { - switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - LocStart = LocStart.getLocWithOffset(argPtr-startBuf); - ReplaceText(LocStart, 1, "*"); - break; - } - } - return; -} - -void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { - SourceLocation DeclLoc = FD->getLocation(); - unsigned parenCount = 0; - - // We have 1 or more arguments that have closure pointers. - const char *startBuf = SM->getCharacterData(DeclLoc); - const char *startArgList = strchr(startBuf, '('); - - assert((*startArgList == '(') && "Rewriter fuzzy parser confused"); - - parenCount++; - // advance the location to startArgList. - DeclLoc = DeclLoc.getLocWithOffset(startArgList-startBuf); - assert((DeclLoc.isValid()) && "Invalid DeclLoc"); - - const char *argPtr = startArgList; - - while (*argPtr++ && parenCount) { - switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - DeclLoc = DeclLoc.getLocWithOffset(argPtr-startArgList); - ReplaceText(DeclLoc, 1, "*"); - break; - case '(': - parenCount++; - break; - case ')': - parenCount--; - break; - } - } - return; -} - -bool RewriteObjC::PointerTypeTakesAnyBlockArguments(QualType QT) { - const FunctionProtoType *FTP; - const PointerType *PT = QT->getAs<PointerType>(); - if (PT) { - FTP = PT->getPointeeType()->getAs<FunctionProtoType>(); - } else { - const BlockPointerType *BPT = QT->getAs<BlockPointerType>(); - assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); - FTP = BPT->getPointeeType()->getAs<FunctionProtoType>(); - } - if (FTP) { - for (const auto &I : FTP->param_types()) - if (isTopLevelBlockPointerType(I)) - return true; - } - return false; -} - -bool RewriteObjC::PointerTypeTakesAnyObjCQualifiedType(QualType QT) { - const FunctionProtoType *FTP; - const PointerType *PT = QT->getAs<PointerType>(); - if (PT) { - FTP = PT->getPointeeType()->getAs<FunctionProtoType>(); - } else { - const BlockPointerType *BPT = QT->getAs<BlockPointerType>(); - assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); - FTP = BPT->getPointeeType()->getAs<FunctionProtoType>(); - } - if (FTP) { - for (const auto &I : FTP->param_types()) { - if (I->isObjCQualifiedIdType()) - return true; - if (I->isObjCObjectPointerType() && - I->getPointeeType()->isObjCQualifiedInterfaceType()) - return true; - } - - } - return false; -} - -void RewriteObjC::GetExtentOfArgList(const char *Name, const char *&LParen, - const char *&RParen) { - const char *argPtr = strchr(Name, '('); - assert((*argPtr == '(') && "Rewriter fuzzy parser confused"); - - LParen = argPtr; // output the start. - argPtr++; // skip past the left paren. - unsigned parenCount = 1; - - while (*argPtr && parenCount) { - switch (*argPtr) { - case '(': parenCount++; break; - case ')': parenCount--; break; - default: break; - } - if (parenCount) argPtr++; - } - assert((*argPtr == ')') && "Rewriter fuzzy parser confused"); - RParen = argPtr; // output the end -} - -void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { - RewriteBlockPointerFunctionArgs(FD); - return; - } - // Handle Variables and Typedefs. - SourceLocation DeclLoc = ND->getLocation(); - QualType DeclT; - if (VarDecl *VD = dyn_cast<VarDecl>(ND)) - DeclT = VD->getType(); - else if (TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(ND)) - DeclT = TDD->getUnderlyingType(); - else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND)) - DeclT = FD->getType(); - else - llvm_unreachable("RewriteBlockPointerDecl(): Decl type not yet handled"); - - const char *startBuf = SM->getCharacterData(DeclLoc); - const char *endBuf = startBuf; - // scan backward (from the decl location) for the end of the previous decl. - while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart) - startBuf--; - SourceLocation Start = DeclLoc.getLocWithOffset(startBuf-endBuf); - std::string buf; - unsigned OrigLength=0; - // *startBuf != '^' if we are dealing with a pointer to function that - // may take block argument types (which will be handled below). - if (*startBuf == '^') { - // Replace the '^' with '*', computing a negative offset. - buf = '*'; - startBuf++; - OrigLength++; - } - while (*startBuf != ')') { - buf += *startBuf; - startBuf++; - OrigLength++; - } - buf += ')'; - OrigLength++; - - if (PointerTypeTakesAnyBlockArguments(DeclT) || - PointerTypeTakesAnyObjCQualifiedType(DeclT)) { - // Replace the '^' with '*' for arguments. - // Replace id<P> with id/*<>*/ - DeclLoc = ND->getLocation(); - startBuf = SM->getCharacterData(DeclLoc); - const char *argListBegin, *argListEnd; - GetExtentOfArgList(startBuf, argListBegin, argListEnd); - while (argListBegin < argListEnd) { - if (*argListBegin == '^') - buf += '*'; - else if (*argListBegin == '<') { - buf += "/*"; - buf += *argListBegin++; - OrigLength++; - while (*argListBegin != '>') { - buf += *argListBegin++; - OrigLength++; - } - buf += *argListBegin; - buf += "*/"; - } - else - buf += *argListBegin; - argListBegin++; - OrigLength++; - } - buf += ')'; - OrigLength++; - } - ReplaceText(Start, OrigLength, buf); - - return; -} - - -/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes: -/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst, -/// struct Block_byref_id_object *src) { -/// _Block_object_assign (&_dest->object, _src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT -/// [|BLOCK_FIELD_IS_WEAK]) // object -/// _Block_object_assign(&_dest->object, _src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK -/// [|BLOCK_FIELD_IS_WEAK]) // block -/// } -/// And: -/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) { -/// _Block_object_dispose(_src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT -/// [|BLOCK_FIELD_IS_WEAK]) // object -/// _Block_object_dispose(_src->object, -/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK -/// [|BLOCK_FIELD_IS_WEAK]) // block -/// } - -std::string RewriteObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD, - int flag) { - std::string S; - if (CopyDestroyCache.count(flag)) - return S; - CopyDestroyCache.insert(flag); - S = "static void __Block_byref_id_object_copy_"; - S += utostr(flag); - S += "(void *dst, void *src) {\n"; - - // offset into the object pointer is computed as: - // void * + void* + int + int + void* + void * - unsigned IntSize = - static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); - unsigned VoidPtrSize = - static_cast<unsigned>(Context->getTypeSize(Context->VoidPtrTy)); - - unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/Context->getCharWidth(); - S += " _Block_object_assign((char*)dst + "; - S += utostr(offset); - S += ", *(void * *) ((char*)src + "; - S += utostr(offset); - S += "), "; - S += utostr(flag); - S += ");\n}\n"; - - S += "static void __Block_byref_id_object_dispose_"; - S += utostr(flag); - S += "(void *src) {\n"; - S += " _Block_object_dispose(*(void * *) ((char*)src + "; - S += utostr(offset); - S += "), "; - S += utostr(flag); - S += ");\n}\n"; - return S; -} - -/// RewriteByRefVar - For each __block typex ND variable this routine transforms -/// the declaration into: -/// struct __Block_byref_ND { -/// void *__isa; // NULL for everything except __weak pointers -/// struct __Block_byref_ND *__forwarding; -/// int32_t __flags; -/// int32_t __size; -/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object -/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object -/// typex ND; -/// }; -/// -/// It then replaces declaration of ND variable with: -/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag, -/// __size=sizeof(struct __Block_byref_ND), -/// ND=initializer-if-any}; -/// -/// -void RewriteObjC::RewriteByRefVar(VarDecl *ND) { - // Insert declaration for the function in which block literal is - // used. - if (CurFunctionDeclToDeclareForBlock) - RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); - int flag = 0; - int isa = 0; - SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); - if (DeclLoc.isInvalid()) - // If type location is missing, it is because of missing type (a warning). - // Use variable's location which is good for this case. - DeclLoc = ND->getLocation(); - const char *startBuf = SM->getCharacterData(DeclLoc); - SourceLocation X = ND->getLocEnd(); - X = SM->getExpansionLoc(X); - const char *endBuf = SM->getCharacterData(X); - std::string Name(ND->getNameAsString()); - std::string ByrefType; - RewriteByRefString(ByrefType, Name, ND, true); - ByrefType += " {\n"; - ByrefType += " void *__isa;\n"; - RewriteByRefString(ByrefType, Name, ND); - ByrefType += " *__forwarding;\n"; - ByrefType += " int __flags;\n"; - ByrefType += " int __size;\n"; - // Add void *__Block_byref_id_object_copy; - // void *__Block_byref_id_object_dispose; if needed. - QualType Ty = ND->getType(); - bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty, ND); - if (HasCopyAndDispose) { - ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n"; - ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n"; - } - - QualType T = Ty; - (void)convertBlockPointerToFunctionPointer(T); - T.getAsStringInternal(Name, Context->getPrintingPolicy()); - - ByrefType += " " + Name + ";\n"; - ByrefType += "};\n"; - // Insert this type in global scope. It is needed by helper function. - SourceLocation FunLocStart; - if (CurFunctionDef) - FunLocStart = CurFunctionDef->getTypeSpecStartLoc(); - else { - assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null"); - FunLocStart = CurMethodDef->getLocStart(); - } - InsertText(FunLocStart, ByrefType); - if (Ty.isObjCGCWeak()) { - flag |= BLOCK_FIELD_IS_WEAK; - isa = 1; - } - - if (HasCopyAndDispose) { - flag = BLOCK_BYREF_CALLER; - QualType Ty = ND->getType(); - // FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well. - if (Ty->isBlockPointerType()) - flag |= BLOCK_FIELD_IS_BLOCK; - else - flag |= BLOCK_FIELD_IS_OBJECT; - std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag); - if (!HF.empty()) - InsertText(FunLocStart, HF); - } - - // struct __Block_byref_ND ND = - // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND), - // initializer-if-any}; - bool hasInit = (ND->getInit() != nullptr); - unsigned flags = 0; - if (HasCopyAndDispose) - flags |= BLOCK_HAS_COPY_DISPOSE; - Name = ND->getNameAsString(); - ByrefType.clear(); - RewriteByRefString(ByrefType, Name, ND); - std::string ForwardingCastType("("); - ForwardingCastType += ByrefType + " *)"; - if (!hasInit) { - ByrefType += " " + Name + " = {(void*)"; - ByrefType += utostr(isa); - ByrefType += "," + ForwardingCastType + "&" + Name + ", "; - ByrefType += utostr(flags); - ByrefType += ", "; - ByrefType += "sizeof("; - RewriteByRefString(ByrefType, Name, ND); - ByrefType += ")"; - if (HasCopyAndDispose) { - ByrefType += ", __Block_byref_id_object_copy_"; - ByrefType += utostr(flag); - ByrefType += ", __Block_byref_id_object_dispose_"; - ByrefType += utostr(flag); - } - ByrefType += "};\n"; - unsigned nameSize = Name.size(); - // for block or function pointer declaration. Name is aleady - // part of the declaration. - if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) - nameSize = 1; - ReplaceText(DeclLoc, endBuf-startBuf+nameSize, ByrefType); - } - else { - SourceLocation startLoc; - Expr *E = ND->getInit(); - if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) - startLoc = ECE->getLParenLoc(); - else - startLoc = E->getLocStart(); - startLoc = SM->getExpansionLoc(startLoc); - endBuf = SM->getCharacterData(startLoc); - ByrefType += " " + Name; - ByrefType += " = {(void*)"; - ByrefType += utostr(isa); - ByrefType += "," + ForwardingCastType + "&" + Name + ", "; - ByrefType += utostr(flags); - ByrefType += ", "; - ByrefType += "sizeof("; - RewriteByRefString(ByrefType, Name, ND); - ByrefType += "), "; - if (HasCopyAndDispose) { - ByrefType += "__Block_byref_id_object_copy_"; - ByrefType += utostr(flag); - ByrefType += ", __Block_byref_id_object_dispose_"; - ByrefType += utostr(flag); - ByrefType += ", "; - } - ReplaceText(DeclLoc, endBuf-startBuf, ByrefType); - - // Complete the newly synthesized compound expression by inserting a right - // curly brace before the end of the declaration. - // FIXME: This approach avoids rewriting the initializer expression. It - // also assumes there is only one declarator. For example, the following - // isn't currently supported by this routine (in general): - // - // double __block BYREFVAR = 1.34, BYREFVAR2 = 1.37; - // - const char *startInitializerBuf = SM->getCharacterData(startLoc); - const char *semiBuf = strchr(startInitializerBuf, ';'); - assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'"); - SourceLocation semiLoc = - startLoc.getLocWithOffset(semiBuf-startInitializerBuf); - - InsertText(semiLoc, "}"); - } - return; -} - -void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { - // Add initializers for any closure decl refs. - GetBlockDeclRefExprs(Exp->getBody()); - if (BlockDeclRefs.size()) { - // Unique all "by copy" declarations. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (!BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>()) { - if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { - BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); - BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl()); - } - } - // Unique all "by ref" declarations. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>()) { - if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { - BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); - BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl()); - } - } - // Find any imported blocks...they will need special attention. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>() || - BlockDeclRefs[i]->getType()->isObjCObjectPointerType() || - BlockDeclRefs[i]->getType()->isBlockPointerType()) - ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl()); - } -} - -FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) { - IdentifierInfo *ID = &Context->Idents.get(name); - QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy); - return FunctionDecl::Create(*Context, TUDecl, SourceLocation(), - SourceLocation(), ID, FType, nullptr, SC_Extern, - false, false); -} - -Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, - const SmallVectorImpl<DeclRefExpr *> &InnerBlockDeclRefs) { - const BlockDecl *block = Exp->getBlockDecl(); - Blocks.push_back(Exp); - - CollectBlockDeclRefInfo(Exp); - - // Add inner imported variables now used in current block. - int countOfInnerDecls = 0; - if (!InnerBlockDeclRefs.empty()) { - for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) { - DeclRefExpr *Exp = InnerBlockDeclRefs[i]; - ValueDecl *VD = Exp->getDecl(); - if (!VD->hasAttr<BlocksAttr>() && !BlockByCopyDeclsPtrSet.count(VD)) { - // We need to save the copied-in variables in nested - // blocks because it is needed at the end for some of the API generations. - // See SynthesizeBlockLiterals routine. - InnerDeclRefs.push_back(Exp); countOfInnerDecls++; - BlockDeclRefs.push_back(Exp); - BlockByCopyDeclsPtrSet.insert(VD); - BlockByCopyDecls.push_back(VD); - } - if (VD->hasAttr<BlocksAttr>() && !BlockByRefDeclsPtrSet.count(VD)) { - InnerDeclRefs.push_back(Exp); countOfInnerDecls++; - BlockDeclRefs.push_back(Exp); - BlockByRefDeclsPtrSet.insert(VD); - BlockByRefDecls.push_back(VD); - } - } - // Find any imported blocks...they will need special attention. - for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) - if (InnerBlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>() || - InnerBlockDeclRefs[i]->getType()->isObjCObjectPointerType() || - InnerBlockDeclRefs[i]->getType()->isBlockPointerType()) - ImportedBlockDecls.insert(InnerBlockDeclRefs[i]->getDecl()); - } - InnerDeclRefsCount.push_back(countOfInnerDecls); - - std::string FuncName; - - if (CurFunctionDef) - FuncName = CurFunctionDef->getNameAsString(); - else if (CurMethodDef) - BuildUniqueMethodName(FuncName, CurMethodDef); - else if (GlobalVarDecl) - FuncName = std::string(GlobalVarDecl->getNameAsString()); - - std::string BlockNumber = utostr(Blocks.size()-1); - - std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber; - std::string Func = "__" + FuncName + "_block_func_" + BlockNumber; - - // Get a pointer to the function type so we can cast appropriately. - QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType()); - QualType FType = Context->getPointerType(BFT); - - FunctionDecl *FD; - Expr *NewRep; - - // Simulate a constructor call... - FD = SynthBlockInitFunctionDecl(Tag); - DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, FType, VK_RValue, - SourceLocation()); - - SmallVector<Expr*, 4> InitExprs; - - // Initialize the block function. - FD = SynthBlockInitFunctionDecl(Func); - DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, false, FD->getType(), - VK_LValue, SourceLocation()); - CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, - CK_BitCast, Arg); - InitExprs.push_back(castExpr); - - // Initialize the block descriptor. - std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA"; - - VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get(DescData.c_str()), - Context->VoidPtrTy, nullptr, - SC_Static); - UnaryOperator *DescRefExpr = - new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false, - Context->VoidPtrTy, - VK_LValue, - SourceLocation()), - UO_AddrOf, - Context->getPointerType(Context->VoidPtrTy), - VK_RValue, OK_Ordinary, - SourceLocation()); - InitExprs.push_back(DescRefExpr); - - // Add initializers for any closure decl refs. - if (BlockDeclRefs.size()) { - Expr *Exp; - // Output all "by copy" declarations. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - if (isObjCType((*I)->getType())) { - // FIXME: Conform to ABI ([[obj retain] autorelease]). - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, - SourceLocation()); - if (HasLocalVariableExternalStorage(*I)) { - QualType QT = (*I)->getType(); - QT = Context->getPointerType(QT); - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, - OK_Ordinary, SourceLocation()); - } - } else if (isTopLevelBlockPointerType((*I)->getType())) { - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Arg = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, - SourceLocation()); - Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, - CK_BitCast, Arg); - } else { - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, - SourceLocation()); - if (HasLocalVariableExternalStorage(*I)) { - QualType QT = (*I)->getType(); - QT = Context->getPointerType(QT); - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue, - OK_Ordinary, SourceLocation()); - } - - } - InitExprs.push_back(Exp); - } - // Output all "by ref" declarations. - for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - ValueDecl *ND = (*I); - std::string Name(ND->getNameAsString()); - std::string RecName; - RewriteByRefString(RecName, Name, ND, true); - IdentifierInfo *II = &Context->Idents.get(RecName.c_str() - + sizeof("struct")); - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - II); - assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl"); - QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - - FD = SynthBlockInitFunctionDecl((*I)->getName()); - Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue, - SourceLocation()); - bool isNestedCapturedVar = false; - if (block) - for (const auto &CI : block->captures()) { - const VarDecl *variable = CI.getVariable(); - if (variable == ND && CI.isNested()) { - assert (CI.isByRef() && - "SynthBlockInitExpr - captured block variable is not byref"); - isNestedCapturedVar = true; - break; - } - } - // captured nested byref variable has its address passed. Do not take - // its address again. - if (!isNestedCapturedVar) - Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, - Context->getPointerType(Exp->getType()), - VK_RValue, OK_Ordinary, SourceLocation()); - Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); - InitExprs.push_back(Exp); - } - } - if (ImportedBlockDecls.size()) { - // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR - int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR); - unsigned IntSize = - static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); - Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag), - Context->IntTy, SourceLocation()); - InitExprs.push_back(FlagExp); - } - NewRep = new (Context) CallExpr(*Context, DRE, InitExprs, - FType, VK_LValue, SourceLocation()); - NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, - Context->getPointerType(NewRep->getType()), - VK_RValue, OK_Ordinary, SourceLocation()); - NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, - NewRep); - BlockDeclRefs.clear(); - BlockByRefDecls.clear(); - BlockByRefDeclsPtrSet.clear(); - BlockByCopyDecls.clear(); - BlockByCopyDeclsPtrSet.clear(); - ImportedBlockDecls.clear(); - return NewRep; -} - -bool RewriteObjC::IsDeclStmtInForeachHeader(DeclStmt *DS) { - if (const ObjCForCollectionStmt * CS = - dyn_cast<ObjCForCollectionStmt>(Stmts.back())) - return CS->getElement() == DS; - return false; -} - -//===----------------------------------------------------------------------===// -// Function Body / Expression rewriting -//===----------------------------------------------------------------------===// - -Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { - if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || - isa<DoStmt>(S) || isa<ForStmt>(S)) - Stmts.push_back(S); - else if (isa<ObjCForCollectionStmt>(S)) { - Stmts.push_back(S); - ObjCBcLabelNo.push_back(++BcLabelCount); - } - - // Pseudo-object operations and ivar references need special - // treatment because we're going to recursively rewrite them. - if (PseudoObjectExpr *PseudoOp = dyn_cast<PseudoObjectExpr>(S)) { - if (isa<BinaryOperator>(PseudoOp->getSyntacticForm())) { - return RewritePropertyOrImplicitSetter(PseudoOp); - } else { - return RewritePropertyOrImplicitGetter(PseudoOp); - } - } else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) { - return RewriteObjCIvarRefExpr(IvarRefExpr); - } - - SourceRange OrigStmtRange = S->getSourceRange(); - - // Perform a bottom up rewrite of all children. - for (Stmt::child_range CI = S->children(); CI; ++CI) - if (*CI) { - Stmt *childStmt = (*CI); - Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(childStmt); - if (newStmt) { - *CI = newStmt; - } - } - - if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) { - SmallVector<DeclRefExpr *, 8> InnerBlockDeclRefs; - llvm::SmallPtrSet<const DeclContext *, 8> InnerContexts; - InnerContexts.insert(BE->getBlockDecl()); - ImportedLocalExternalDecls.clear(); - GetInnerBlockDeclRefExprs(BE->getBody(), - InnerBlockDeclRefs, InnerContexts); - // Rewrite the block body in place. - Stmt *SaveCurrentBody = CurrentBody; - CurrentBody = BE->getBody(); - PropParentMap = nullptr; - // block literal on rhs of a property-dot-sytax assignment - // must be replaced by its synthesize ast so getRewrittenText - // works as expected. In this case, what actually ends up on RHS - // is the blockTranscribed which is the helper function for the - // block literal; as in: self.c = ^() {[ace ARR];}; - bool saveDisableReplaceStmt = DisableReplaceStmt; - DisableReplaceStmt = false; - RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); - DisableReplaceStmt = saveDisableReplaceStmt; - CurrentBody = SaveCurrentBody; - PropParentMap = nullptr; - ImportedLocalExternalDecls.clear(); - // Now we snarf the rewritten text and stash it away for later use. - std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); - RewrittenBlockExprs[BE] = Str; - - Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs); - - //blockTranscribed->dump(); - ReplaceStmt(S, blockTranscribed); - return blockTranscribed; - } - // Handle specific things. - if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S)) - return RewriteAtEncode(AtEncode); - - if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S)) - return RewriteAtSelector(AtSelector); - - if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S)) - return RewriteObjCStringLiteral(AtString); - - if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) { -#if 0 - // Before we rewrite it, put the original message expression in a comment. - SourceLocation startLoc = MessExpr->getLocStart(); - SourceLocation endLoc = MessExpr->getLocEnd(); - - const char *startBuf = SM->getCharacterData(startLoc); - const char *endBuf = SM->getCharacterData(endLoc); - - std::string messString; - messString += "// "; - messString.append(startBuf, endBuf-startBuf+1); - messString += "\n"; - - // FIXME: Missing definition of - // InsertText(clang::SourceLocation, char const*, unsigned int). - // InsertText(startLoc, messString.c_str(), messString.size()); - // Tried this, but it didn't work either... - // ReplaceText(startLoc, 0, messString.c_str(), messString.size()); -#endif - return RewriteMessageExpr(MessExpr); - } - - if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S)) - return RewriteObjCTryStmt(StmtTry); - - if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S)) - return RewriteObjCSynchronizedStmt(StmtTry); - - if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S)) - return RewriteObjCThrowStmt(StmtThrow); - - if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S)) - return RewriteObjCProtocolExpr(ProtocolExp); - - if (ObjCForCollectionStmt *StmtForCollection = - dyn_cast<ObjCForCollectionStmt>(S)) - return RewriteObjCForCollectionStmt(StmtForCollection, - OrigStmtRange.getEnd()); - if (BreakStmt *StmtBreakStmt = - dyn_cast<BreakStmt>(S)) - return RewriteBreakStmt(StmtBreakStmt); - if (ContinueStmt *StmtContinueStmt = - dyn_cast<ContinueStmt>(S)) - return RewriteContinueStmt(StmtContinueStmt); - - // Need to check for protocol refs (id <P>, Foo <P> *) in variable decls - // and cast exprs. - if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) { - // FIXME: What we're doing here is modifying the type-specifier that - // precedes the first Decl. In the future the DeclGroup should have - // a separate type-specifier that we can rewrite. - // NOTE: We need to avoid rewriting the DeclStmt if it is within - // the context of an ObjCForCollectionStmt. For example: - // NSArray *someArray; - // for (id <FooProtocol> index in someArray) ; - // This is because RewriteObjCForCollectionStmt() does textual rewriting - // and it depends on the original text locations/positions. - if (Stmts.empty() || !IsDeclStmtInForeachHeader(DS)) - RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin()); - - // Blocks rewrite rules. - for (auto *SD : DS->decls()) { - if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) { - if (isTopLevelBlockPointerType(ND->getType())) - RewriteBlockPointerDecl(ND); - else if (ND->getType()->isFunctionPointerType()) - CheckFunctionPointerDecl(ND->getType(), ND); - if (VarDecl *VD = dyn_cast<VarDecl>(SD)) { - if (VD->hasAttr<BlocksAttr>()) { - static unsigned uniqueByrefDeclCount = 0; - assert(!BlockByRefDeclNo.count(ND) && - "RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl"); - BlockByRefDeclNo[ND] = uniqueByrefDeclCount++; - RewriteByRefVar(VD); - } - else - RewriteTypeOfDecl(VD); - } - } - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) { - if (isTopLevelBlockPointerType(TD->getUnderlyingType())) - RewriteBlockPointerDecl(TD); - else if (TD->getUnderlyingType()->isFunctionPointerType()) - CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - } - } - } - - if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S)) - RewriteObjCQualifiedInterfaceTypes(CE); - - if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || - isa<DoStmt>(S) || isa<ForStmt>(S)) { - assert(!Stmts.empty() && "Statement stack is empty"); - assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) || - isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back())) - && "Statement stack mismatch"); - Stmts.pop_back(); - } - // Handle blocks rewriting. - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) { - ValueDecl *VD = DRE->getDecl(); - if (VD->hasAttr<BlocksAttr>()) - return RewriteBlockDeclRefExpr(DRE); - if (HasLocalVariableExternalStorage(VD)) - return RewriteLocalVariableExternalStorage(DRE); - } - - if (CallExpr *CE = dyn_cast<CallExpr>(S)) { - if (CE->getCallee()->getType()->isBlockPointerType()) { - Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee()); - ReplaceStmt(S, BlockCall); - return BlockCall; - } - } - if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S)) { - RewriteCastExpr(CE); - } -#if 0 - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) { - CastExpr *Replacement = new (Context) CastExpr(ICE->getType(), - ICE->getSubExpr(), - SourceLocation()); - // Get the new text. - std::string SStr; - llvm::raw_string_ostream Buf(SStr); - Replacement->printPretty(Buf); - const std::string &Str = Buf.str(); - - printf("CAST = %s\n", &Str[0]); - InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size()); - delete S; - return Replacement; - } -#endif - // Return this stmt unmodified. - return S; -} - -void RewriteObjC::RewriteRecordBody(RecordDecl *RD) { - for (auto *FD : RD->fields()) { - if (isTopLevelBlockPointerType(FD->getType())) - RewriteBlockPointerDecl(FD); - if (FD->getType()->isObjCQualifiedIdType() || - FD->getType()->isObjCQualifiedInterfaceType()) - RewriteObjCQualifiedInterfaceTypes(FD); - } -} - -/// HandleDeclInMainFile - This is called for each top-level decl defined in the -/// main file of the input. -void RewriteObjC::HandleDeclInMainFile(Decl *D) { - switch (D->getKind()) { - case Decl::Function: { - FunctionDecl *FD = cast<FunctionDecl>(D); - if (FD->isOverloadedOperator()) - return; - - // Since function prototypes don't have ParmDecl's, we check the function - // prototype. This enables us to rewrite function declarations and - // definitions using the same code. - RewriteBlocksInFunctionProtoType(FD->getType(), FD); - - if (!FD->isThisDeclarationADefinition()) - break; - - // FIXME: If this should support Obj-C++, support CXXTryStmt - if (CompoundStmt *Body = dyn_cast_or_null<CompoundStmt>(FD->getBody())) { - CurFunctionDef = FD; - CurFunctionDeclToDeclareForBlock = FD; - CurrentBody = Body; - Body = - cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body)); - FD->setBody(Body); - CurrentBody = nullptr; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = nullptr; - } - // This synthesizes and inserts the block "impl" struct, invoke function, - // and any copy/dispose helper functions. - InsertBlockLiteralsWithinFunction(FD); - CurFunctionDef = nullptr; - CurFunctionDeclToDeclareForBlock = nullptr; - } - break; - } - case Decl::ObjCMethod: { - ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D); - if (CompoundStmt *Body = MD->getCompoundBody()) { - CurMethodDef = MD; - CurrentBody = Body; - Body = - cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body)); - MD->setBody(Body); - CurrentBody = nullptr; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = nullptr; - } - InsertBlockLiteralsWithinMethod(MD); - CurMethodDef = nullptr; - } - break; - } - case Decl::ObjCImplementation: { - ObjCImplementationDecl *CI = cast<ObjCImplementationDecl>(D); - ClassImplementation.push_back(CI); - break; - } - case Decl::ObjCCategoryImpl: { - ObjCCategoryImplDecl *CI = cast<ObjCCategoryImplDecl>(D); - CategoryImplementation.push_back(CI); - break; - } - case Decl::Var: { - VarDecl *VD = cast<VarDecl>(D); - RewriteObjCQualifiedInterfaceTypes(VD); - if (isTopLevelBlockPointerType(VD->getType())) - RewriteBlockPointerDecl(VD); - else if (VD->getType()->isFunctionPointerType()) { - CheckFunctionPointerDecl(VD->getType(), VD); - if (VD->getInit()) { - if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) { - RewriteCastExpr(CE); - } - } - } else if (VD->getType()->isRecordType()) { - RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl(); - if (RD->isCompleteDefinition()) - RewriteRecordBody(RD); - } - if (VD->getInit()) { - GlobalVarDecl = VD; - CurrentBody = VD->getInit(); - RewriteFunctionBodyOrGlobalInitializer(VD->getInit()); - CurrentBody = nullptr; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = nullptr; - } - SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName()); - GlobalVarDecl = nullptr; - - // This is needed for blocks. - if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) { - RewriteCastExpr(CE); - } - } - break; - } - case Decl::TypeAlias: - case Decl::Typedef: { - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { - if (isTopLevelBlockPointerType(TD->getUnderlyingType())) - RewriteBlockPointerDecl(TD); - else if (TD->getUnderlyingType()->isFunctionPointerType()) - CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - } - break; - } - case Decl::CXXRecord: - case Decl::Record: { - RecordDecl *RD = cast<RecordDecl>(D); - if (RD->isCompleteDefinition()) - RewriteRecordBody(RD); - break; - } - default: - break; - } - // Nothing yet. -} - -void RewriteObjC::HandleTranslationUnit(ASTContext &C) { - if (Diags.hasErrorOccurred()) - return; - - RewriteInclude(); - - // Here's a great place to add any extra declarations that may be needed. - // Write out meta data for each @protocol(<expr>). - for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(), - E = ProtocolExprDecls.end(); I != E; ++I) - RewriteObjCProtocolMetaData(*I, "", "", Preamble); - - InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false); - if (ClassImplementation.size() || CategoryImplementation.size()) - RewriteImplementations(); - - // Get the buffer corresponding to MainFileID. If we haven't changed it, then - // we are done. - if (const RewriteBuffer *RewriteBuf = - Rewrite.getRewriteBufferFor(MainFileID)) { - //printf("Changed:\n"); - *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); - } else { - llvm::errs() << "No changes\n"; - } - - if (ClassImplementation.size() || CategoryImplementation.size() || - ProtocolExprDecls.size()) { - // Rewrite Objective-c meta data* - std::string ResultStr; - RewriteMetaDataIntoBuffer(ResultStr); - // Emit metadata. - *OutFile << ResultStr; - } - OutFile->flush(); -} - -void RewriteObjCFragileABI::Initialize(ASTContext &context) { - InitializeCommon(context); - - // declaring objc_selector outside the parameter list removes a silly - // scope related warning... - if (IsHeader) - Preamble = "#pragma once\n"; - Preamble += "struct objc_selector; struct objc_class;\n"; - Preamble += "struct __rw_objc_super { struct objc_object *object; "; - Preamble += "struct objc_object *superClass; "; - if (LangOpts.MicrosoftExt) { - // Add a constructor for creating temporary objects. - Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) " - ": "; - Preamble += "object(o), superClass(s) {} "; - } - Preamble += "};\n"; - Preamble += "#ifndef _REWRITER_typedef_Protocol\n"; - Preamble += "typedef struct objc_object Protocol;\n"; - Preamble += "#define _REWRITER_typedef_Protocol\n"; - Preamble += "#endif\n"; - if (LangOpts.MicrosoftExt) { - Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n"; - Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n"; - } else - Preamble += "#define __OBJC_RW_DLLIMPORT extern\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend"; - Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper"; - Preamble += "(struct objc_super *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSend_stret"; - Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSendSuper_stret"; - Preamble += "(struct objc_super *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret"; - Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass"; - Preamble += "(const char *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass"; - Preamble += "(struct objc_class *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass"; - Preamble += "(const char *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_enter(void *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_exit(void *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_exception_extract(void *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match"; - Preamble += "(struct objc_class *, struct objc_object *);\n"; - // @synchronized hooks. - Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_enter(struct objc_object *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_exit(struct objc_object *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n"; - Preamble += "#ifndef __FASTENUMERATIONSTATE\n"; - Preamble += "struct __objcFastEnumerationState {\n\t"; - Preamble += "unsigned long state;\n\t"; - Preamble += "void **itemsPtr;\n\t"; - Preamble += "unsigned long *mutationsPtr;\n\t"; - Preamble += "unsigned long extra[5];\n};\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n"; - Preamble += "#define __FASTENUMERATIONSTATE\n"; - Preamble += "#endif\n"; - Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n"; - Preamble += "struct __NSConstantStringImpl {\n"; - Preamble += " int *isa;\n"; - Preamble += " int flags;\n"; - Preamble += " char *str;\n"; - Preamble += " long length;\n"; - Preamble += "};\n"; - Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n"; - Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n"; - Preamble += "#else\n"; - Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n"; - Preamble += "#endif\n"; - Preamble += "#define __NSCONSTANTSTRINGIMPL\n"; - Preamble += "#endif\n"; - // Blocks preamble. - Preamble += "#ifndef BLOCK_IMPL\n"; - Preamble += "#define BLOCK_IMPL\n"; - Preamble += "struct __block_impl {\n"; - Preamble += " void *isa;\n"; - Preamble += " int Flags;\n"; - Preamble += " int Reserved;\n"; - Preamble += " void *FuncPtr;\n"; - Preamble += "};\n"; - Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n"; - Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n"; - Preamble += "extern \"C\" __declspec(dllexport) " - "void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n"; - Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n"; - Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n"; - Preamble += "#else\n"; - Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n"; - Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n"; - Preamble += "#endif\n"; - Preamble += "#endif\n"; - if (LangOpts.MicrosoftExt) { - Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; - Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; - Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests. - Preamble += "#define __attribute__(X)\n"; - Preamble += "#endif\n"; - Preamble += "#define __weak\n"; - } - else { - Preamble += "#define __block\n"; - Preamble += "#define __weak\n"; - } - // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long - // as this avoids warning in any 64bit/32bit compilation model. - Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n"; -} - -/// RewriteIvarOffsetComputation - This rutine synthesizes computation of -/// ivar offset. -void RewriteObjCFragileABI::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, - std::string &Result) { - if (ivar->isBitField()) { - // FIXME: The hack below doesn't work for bitfields. For now, we simply - // place all bitfields at offset 0. - Result += "0"; - } else { - Result += "__OFFSETOFIVAR__(struct "; - Result += ivar->getContainingInterface()->getNameAsString(); - if (LangOpts.MicrosoftExt) - Result += "_IMPL"; - Result += ", "; - Result += ivar->getNameAsString(); - Result += ")"; - } -} - -/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data. -void RewriteObjCFragileABI::RewriteObjCProtocolMetaData( - ObjCProtocolDecl *PDecl, StringRef prefix, - StringRef ClassName, std::string &Result) { - static bool objc_protocol_methods = false; - - // Output struct protocol_methods holder of method selector and type. - if (!objc_protocol_methods && PDecl->hasDefinition()) { - /* struct protocol_methods { - SEL _cmd; - char *method_types; - } - */ - Result += "\nstruct _protocol_methods {\n"; - Result += "\tstruct objc_selector *_cmd;\n"; - Result += "\tchar *method_types;\n"; - Result += "};\n"; - - objc_protocol_methods = true; - } - // Do not synthesize the protocol more than once. - if (ObjCSynthesizedProtocols.count(PDecl->getCanonicalDecl())) - return; - - if (ObjCProtocolDecl *Def = PDecl->getDefinition()) - PDecl = Def; - - if (PDecl->instmeth_begin() != PDecl->instmeth_end()) { - unsigned NumMethods = std::distance(PDecl->instmeth_begin(), - PDecl->instmeth_end()); - /* struct _objc_protocol_method_list { - int protocol_method_count; - struct protocol_methods protocols[]; - } - */ - Result += "\nstatic struct {\n"; - Result += "\tint protocol_method_count;\n"; - Result += "\tstruct _protocol_methods protocol_methods["; - Result += utostr(NumMethods); - Result += "];\n} _OBJC_PROTOCOL_INSTANCE_METHODS_"; - Result += PDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__OBJC, __cat_inst_meth\")))= " - "{\n\t" + utostr(NumMethods) + "\n"; - - // Output instance methods declared in this protocol. - for (ObjCProtocolDecl::instmeth_iterator - I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); - I != E; ++I) { - if (I == PDecl->instmeth_begin()) - Result += "\t ,{{(struct objc_selector *)\""; - else - Result += "\t ,{(struct objc_selector *)\""; - Result += (*I)->getSelector().getAsString(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl((*I), MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\"}\n"; - } - Result += "\t }\n};\n"; - } - - // Output class methods declared in this protocol. - unsigned NumMethods = std::distance(PDecl->classmeth_begin(), - PDecl->classmeth_end()); - if (NumMethods > 0) { - /* struct _objc_protocol_method_list { - int protocol_method_count; - struct protocol_methods protocols[]; - } - */ - Result += "\nstatic struct {\n"; - Result += "\tint protocol_method_count;\n"; - Result += "\tstruct _protocol_methods protocol_methods["; - Result += utostr(NumMethods); - Result += "];\n} _OBJC_PROTOCOL_CLASS_METHODS_"; - Result += PDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= " - "{\n\t"; - Result += utostr(NumMethods); - Result += "\n"; - - // Output instance methods declared in this protocol. - for (ObjCProtocolDecl::classmeth_iterator - I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); - I != E; ++I) { - if (I == PDecl->classmeth_begin()) - Result += "\t ,{{(struct objc_selector *)\""; - else - Result += "\t ,{(struct objc_selector *)\""; - Result += (*I)->getSelector().getAsString(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl((*I), MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\"}\n"; - } - Result += "\t }\n};\n"; - } - - // Output: - /* struct _objc_protocol { - // Objective-C 1.0 extensions - struct _objc_protocol_extension *isa; - char *protocol_name; - struct _objc_protocol **protocol_list; - struct _objc_protocol_method_list *instance_methods; - struct _objc_protocol_method_list *class_methods; - }; - */ - static bool objc_protocol = false; - if (!objc_protocol) { - Result += "\nstruct _objc_protocol {\n"; - Result += "\tstruct _objc_protocol_extension *isa;\n"; - Result += "\tchar *protocol_name;\n"; - Result += "\tstruct _objc_protocol **protocol_list;\n"; - Result += "\tstruct _objc_protocol_method_list *instance_methods;\n"; - Result += "\tstruct _objc_protocol_method_list *class_methods;\n"; - Result += "};\n"; - - objc_protocol = true; - } - - Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_"; - Result += PDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__OBJC, __protocol\")))= " - "{\n\t0, \""; - Result += PDecl->getNameAsString(); - Result += "\", 0, "; - if (PDecl->instmeth_begin() != PDecl->instmeth_end()) { - Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_INSTANCE_METHODS_"; - Result += PDecl->getNameAsString(); - Result += ", "; - } - else - Result += "0, "; - if (PDecl->classmeth_begin() != PDecl->classmeth_end()) { - Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_CLASS_METHODS_"; - Result += PDecl->getNameAsString(); - Result += "\n"; - } - else - Result += "0\n"; - Result += "};\n"; - - // Mark this protocol as having been generated. - if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl())) - llvm_unreachable("protocol already synthesized"); - -} - -void RewriteObjCFragileABI::RewriteObjCProtocolListMetaData( - const ObjCList<ObjCProtocolDecl> &Protocols, - StringRef prefix, StringRef ClassName, - std::string &Result) { - if (Protocols.empty()) return; - - for (unsigned i = 0; i != Protocols.size(); i++) - RewriteObjCProtocolMetaData(Protocols[i], prefix, ClassName, Result); - - // Output the top lovel protocol meta-data for the class. - /* struct _objc_protocol_list { - struct _objc_protocol_list *next; - int protocol_count; - struct _objc_protocol *class_protocols[]; - } - */ - Result += "\nstatic struct {\n"; - Result += "\tstruct _objc_protocol_list *next;\n"; - Result += "\tint protocol_count;\n"; - Result += "\tstruct _objc_protocol *class_protocols["; - Result += utostr(Protocols.size()); - Result += "];\n} _OBJC_"; - Result += prefix; - Result += "_PROTOCOLS_"; - Result += ClassName; - Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= " - "{\n\t0, "; - Result += utostr(Protocols.size()); - Result += "\n"; - - Result += "\t,{&_OBJC_PROTOCOL_"; - Result += Protocols[0]->getNameAsString(); - Result += " \n"; - - for (unsigned i = 1; i != Protocols.size(); i++) { - Result += "\t ,&_OBJC_PROTOCOL_"; - Result += Protocols[i]->getNameAsString(); - Result += "\n"; - } - Result += "\t }\n};\n"; -} - -void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, - std::string &Result) { - ObjCInterfaceDecl *CDecl = IDecl->getClassInterface(); - - // Explicitly declared @interface's are already synthesized. - if (CDecl->isImplicitInterfaceDecl()) { - // FIXME: Implementation of a class with no @interface (legacy) does not - // produce correct synthesis as yet. - RewriteObjCInternalStruct(CDecl, Result); - } - - // Build _objc_ivar_list metadata for classes ivars if needed - unsigned NumIvars = !IDecl->ivar_empty() - ? IDecl->ivar_size() - : (CDecl ? CDecl->ivar_size() : 0); - if (NumIvars > 0) { - static bool objc_ivar = false; - if (!objc_ivar) { - /* struct _objc_ivar { - char *ivar_name; - char *ivar_type; - int ivar_offset; - }; - */ - Result += "\nstruct _objc_ivar {\n"; - Result += "\tchar *ivar_name;\n"; - Result += "\tchar *ivar_type;\n"; - Result += "\tint ivar_offset;\n"; - Result += "};\n"; - - objc_ivar = true; - } - - /* struct { - int ivar_count; - struct _objc_ivar ivar_list[nIvars]; - }; - */ - Result += "\nstatic struct {\n"; - Result += "\tint ivar_count;\n"; - Result += "\tstruct _objc_ivar ivar_list["; - Result += utostr(NumIvars); - Result += "];\n} _OBJC_INSTANCE_VARIABLES_"; - Result += IDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__OBJC, __instance_vars\")))= " - "{\n\t"; - Result += utostr(NumIvars); - Result += "\n"; - - ObjCInterfaceDecl::ivar_iterator IVI, IVE; - SmallVector<ObjCIvarDecl *, 8> IVars; - if (!IDecl->ivar_empty()) { - for (auto *IV : IDecl->ivars()) - IVars.push_back(IV); - IVI = IDecl->ivar_begin(); - IVE = IDecl->ivar_end(); - } else { - IVI = CDecl->ivar_begin(); - IVE = CDecl->ivar_end(); - } - Result += "\t,{{\""; - Result += IVI->getNameAsString(); - Result += "\", \""; - std::string TmpString, StrEncoding; - Context->getObjCEncodingForType(IVI->getType(), TmpString, *IVI); - QuoteDoublequotes(TmpString, StrEncoding); - Result += StrEncoding; - Result += "\", "; - RewriteIvarOffsetComputation(*IVI, Result); - Result += "}\n"; - for (++IVI; IVI != IVE; ++IVI) { - Result += "\t ,{\""; - Result += IVI->getNameAsString(); - Result += "\", \""; - std::string TmpString, StrEncoding; - Context->getObjCEncodingForType(IVI->getType(), TmpString, *IVI); - QuoteDoublequotes(TmpString, StrEncoding); - Result += StrEncoding; - Result += "\", "; - RewriteIvarOffsetComputation(*IVI, Result); - Result += "}\n"; - } - - Result += "\t }\n};\n"; - } - - // Build _objc_method_list for class's instance methods if needed - SmallVector<ObjCMethodDecl *, 32> InstanceMethods(IDecl->instance_methods()); - - // If any of our property implementations have associated getters or - // setters, produce metadata for them as well. - for (const auto *Prop : IDecl->property_impls()) { - if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - continue; - if (!Prop->getPropertyIvarDecl()) - continue; - ObjCPropertyDecl *PD = Prop->getPropertyDecl(); - if (!PD) - continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) - if (!Getter->isDefined()) - InstanceMethods.push_back(Getter); - if (PD->isReadOnly()) - continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) - if (!Setter->isDefined()) - InstanceMethods.push_back(Setter); - } - RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(), - true, "", IDecl->getName(), Result); - - // Build _objc_method_list for class's class methods if needed - RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(), - false, "", IDecl->getName(), Result); - - // Protocols referenced in class declaration? - RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), - "CLASS", CDecl->getName(), Result); - - // Declaration of class/meta-class metadata - /* struct _objc_class { - struct _objc_class *isa; // or const char *root_class_name when metadata - const char *super_class_name; - char *name; - long version; - long info; - long instance_size; - struct _objc_ivar_list *ivars; - struct _objc_method_list *methods; - struct objc_cache *cache; - struct objc_protocol_list *protocols; - const char *ivar_layout; - struct _objc_class_ext *ext; - }; - */ - static bool objc_class = false; - if (!objc_class) { - Result += "\nstruct _objc_class {\n"; - Result += "\tstruct _objc_class *isa;\n"; - Result += "\tconst char *super_class_name;\n"; - Result += "\tchar *name;\n"; - Result += "\tlong version;\n"; - Result += "\tlong info;\n"; - Result += "\tlong instance_size;\n"; - Result += "\tstruct _objc_ivar_list *ivars;\n"; - Result += "\tstruct _objc_method_list *methods;\n"; - Result += "\tstruct objc_cache *cache;\n"; - Result += "\tstruct _objc_protocol_list *protocols;\n"; - Result += "\tconst char *ivar_layout;\n"; - Result += "\tstruct _objc_class_ext *ext;\n"; - Result += "};\n"; - objc_class = true; - } - - // Meta-class metadata generation. - ObjCInterfaceDecl *RootClass = nullptr; - ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass(); - while (SuperClass) { - RootClass = SuperClass; - SuperClass = SuperClass->getSuperClass(); - } - SuperClass = CDecl->getSuperClass(); - - Result += "\nstatic struct _objc_class _OBJC_METACLASS_"; - Result += CDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__OBJC, __meta_class\")))= " - "{\n\t(struct _objc_class *)\""; - Result += (RootClass ? RootClass->getNameAsString() : CDecl->getNameAsString()); - Result += "\""; - - if (SuperClass) { - Result += ", \""; - Result += SuperClass->getNameAsString(); - Result += "\", \""; - Result += CDecl->getNameAsString(); - Result += "\""; - } - else { - Result += ", 0, \""; - Result += CDecl->getNameAsString(); - Result += "\""; - } - // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it. - // 'info' field is initialized to CLS_META(2) for metaclass - Result += ", 0,2, sizeof(struct _objc_class), 0"; - if (IDecl->classmeth_begin() != IDecl->classmeth_end()) { - Result += "\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_"; - Result += IDecl->getNameAsString(); - Result += "\n"; - } - else - Result += ", 0\n"; - if (CDecl->protocol_begin() != CDecl->protocol_end()) { - Result += "\t,0, (struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_"; - Result += CDecl->getNameAsString(); - Result += ",0,0\n"; - } - else - Result += "\t,0,0,0,0\n"; - Result += "};\n"; - - // class metadata generation. - Result += "\nstatic struct _objc_class _OBJC_CLASS_"; - Result += CDecl->getNameAsString(); - Result += " __attribute__ ((used, section (\"__OBJC, __class\")))= " - "{\n\t&_OBJC_METACLASS_"; - Result += CDecl->getNameAsString(); - if (SuperClass) { - Result += ", \""; - Result += SuperClass->getNameAsString(); - Result += "\", \""; - Result += CDecl->getNameAsString(); - Result += "\""; - } - else { - Result += ", 0, \""; - Result += CDecl->getNameAsString(); - Result += "\""; - } - // 'info' field is initialized to CLS_CLASS(1) for class - Result += ", 0,1"; - if (!ObjCSynthesizedStructs.count(CDecl)) - Result += ",0"; - else { - // class has size. Must synthesize its size. - Result += ",sizeof(struct "; - Result += CDecl->getNameAsString(); - if (LangOpts.MicrosoftExt) - Result += "_IMPL"; - Result += ")"; - } - if (NumIvars > 0) { - Result += ", (struct _objc_ivar_list *)&_OBJC_INSTANCE_VARIABLES_"; - Result += CDecl->getNameAsString(); - Result += "\n\t"; - } - else - Result += ",0"; - if (IDecl->instmeth_begin() != IDecl->instmeth_end()) { - Result += ", (struct _objc_method_list *)&_OBJC_INSTANCE_METHODS_"; - Result += CDecl->getNameAsString(); - Result += ", 0\n\t"; - } - else - Result += ",0,0"; - if (CDecl->protocol_begin() != CDecl->protocol_end()) { - Result += ", (struct _objc_protocol_list*)&_OBJC_CLASS_PROTOCOLS_"; - Result += CDecl->getNameAsString(); - Result += ", 0,0\n"; - } - else - Result += ",0,0,0\n"; - Result += "};\n"; -} - -void RewriteObjCFragileABI::RewriteMetaDataIntoBuffer(std::string &Result) { - int ClsDefCount = ClassImplementation.size(); - int CatDefCount = CategoryImplementation.size(); - - // For each implemented class, write out all its meta data. - for (int i = 0; i < ClsDefCount; i++) - RewriteObjCClassMetaData(ClassImplementation[i], Result); - - // For each implemented category, write out all its meta data. - for (int i = 0; i < CatDefCount; i++) - RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result); - - // Write objc_symtab metadata - /* - struct _objc_symtab - { - long sel_ref_cnt; - SEL *refs; - short cls_def_cnt; - short cat_def_cnt; - void *defs[cls_def_cnt + cat_def_cnt]; - }; - */ - - Result += "\nstruct _objc_symtab {\n"; - Result += "\tlong sel_ref_cnt;\n"; - Result += "\tSEL *refs;\n"; - Result += "\tshort cls_def_cnt;\n"; - Result += "\tshort cat_def_cnt;\n"; - Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n"; - Result += "};\n\n"; - - Result += "static struct _objc_symtab " - "_OBJC_SYMBOLS __attribute__((used, section (\"__OBJC, __symbols\")))= {\n"; - Result += "\t0, 0, " + utostr(ClsDefCount) - + ", " + utostr(CatDefCount) + "\n"; - for (int i = 0; i < ClsDefCount; i++) { - Result += "\t,&_OBJC_CLASS_"; - Result += ClassImplementation[i]->getNameAsString(); - Result += "\n"; - } - - for (int i = 0; i < CatDefCount; i++) { - Result += "\t,&_OBJC_CATEGORY_"; - Result += CategoryImplementation[i]->getClassInterface()->getNameAsString(); - Result += "_"; - Result += CategoryImplementation[i]->getNameAsString(); - Result += "\n"; - } - - Result += "};\n\n"; - - // Write objc_module metadata - - /* - struct _objc_module { - long version; - long size; - const char *name; - struct _objc_symtab *symtab; - } - */ - - Result += "\nstruct _objc_module {\n"; - Result += "\tlong version;\n"; - Result += "\tlong size;\n"; - Result += "\tconst char *name;\n"; - Result += "\tstruct _objc_symtab *symtab;\n"; - Result += "};\n\n"; - Result += "static struct _objc_module " - "_OBJC_MODULES __attribute__ ((used, section (\"__OBJC, __module_info\")))= {\n"; - Result += "\t" + utostr(OBJC_ABI_VERSION) + - ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n"; - Result += "};\n\n"; - - if (LangOpts.MicrosoftExt) { - if (ProtocolExprDecls.size()) { - Result += "#pragma section(\".objc_protocol$B\",long,read,write)\n"; - Result += "#pragma data_seg(push, \".objc_protocol$B\")\n"; - for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(), - E = ProtocolExprDecls.end(); I != E; ++I) { - Result += "static struct _objc_protocol *_POINTER_OBJC_PROTOCOL_"; - Result += (*I)->getNameAsString(); - Result += " = &_OBJC_PROTOCOL_"; - Result += (*I)->getNameAsString(); - Result += ";\n"; - } - Result += "#pragma data_seg(pop)\n\n"; - } - Result += "#pragma section(\".objc_module_info$B\",long,read,write)\n"; - Result += "#pragma data_seg(push, \".objc_module_info$B\")\n"; - Result += "static struct _objc_module *_POINTER_OBJC_MODULES = "; - Result += "&_OBJC_MODULES;\n"; - Result += "#pragma data_seg(pop)\n\n"; - } -} - -/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category -/// implementation. -void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl, - std::string &Result) { - ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface(); - // Find category declaration for this implementation. - ObjCCategoryDecl *CDecl - = ClassDecl->FindCategoryDeclaration(IDecl->getIdentifier()); - - std::string FullCategoryName = ClassDecl->getNameAsString(); - FullCategoryName += '_'; - FullCategoryName += IDecl->getNameAsString(); - - // Build _objc_method_list for class's instance methods if needed - SmallVector<ObjCMethodDecl *, 32> InstanceMethods(IDecl->instance_methods()); - - // If any of our property implementations have associated getters or - // setters, produce metadata for them as well. - for (const auto *Prop : IDecl->property_impls()) { - if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - continue; - if (!Prop->getPropertyIvarDecl()) - continue; - ObjCPropertyDecl *PD = Prop->getPropertyDecl(); - if (!PD) - continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) - InstanceMethods.push_back(Getter); - if (PD->isReadOnly()) - continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) - InstanceMethods.push_back(Setter); - } - RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(), - true, "CATEGORY_", FullCategoryName.c_str(), - Result); - - // Build _objc_method_list for class's class methods if needed - RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(), - false, "CATEGORY_", FullCategoryName.c_str(), - Result); - - // Protocols referenced in class declaration? - // Null CDecl is case of a category implementation with no category interface - if (CDecl) - RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), "CATEGORY", - FullCategoryName, Result); - /* struct _objc_category { - char *category_name; - char *class_name; - struct _objc_method_list *instance_methods; - struct _objc_method_list *class_methods; - struct _objc_protocol_list *protocols; - // Objective-C 1.0 extensions - uint32_t size; // sizeof (struct _objc_category) - struct _objc_property_list *instance_properties; // category's own - // @property decl. - }; - */ - - static bool objc_category = false; - if (!objc_category) { - Result += "\nstruct _objc_category {\n"; - Result += "\tchar *category_name;\n"; - Result += "\tchar *class_name;\n"; - Result += "\tstruct _objc_method_list *instance_methods;\n"; - Result += "\tstruct _objc_method_list *class_methods;\n"; - Result += "\tstruct _objc_protocol_list *protocols;\n"; - Result += "\tunsigned int size;\n"; - Result += "\tstruct _objc_property_list *instance_properties;\n"; - Result += "};\n"; - objc_category = true; - } - Result += "\nstatic struct _objc_category _OBJC_CATEGORY_"; - Result += FullCategoryName; - Result += " __attribute__ ((used, section (\"__OBJC, __category\")))= {\n\t\""; - Result += IDecl->getNameAsString(); - Result += "\"\n\t, \""; - Result += ClassDecl->getNameAsString(); - Result += "\"\n"; - - if (IDecl->instmeth_begin() != IDecl->instmeth_end()) { - Result += "\t, (struct _objc_method_list *)" - "&_OBJC_CATEGORY_INSTANCE_METHODS_"; - Result += FullCategoryName; - Result += "\n"; - } - else - Result += "\t, 0\n"; - if (IDecl->classmeth_begin() != IDecl->classmeth_end()) { - Result += "\t, (struct _objc_method_list *)" - "&_OBJC_CATEGORY_CLASS_METHODS_"; - Result += FullCategoryName; - Result += "\n"; - } - else - Result += "\t, 0\n"; - - if (CDecl && CDecl->protocol_begin() != CDecl->protocol_end()) { - Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_"; - Result += FullCategoryName; - Result += "\n"; - } - else - Result += "\t, 0\n"; - Result += "\t, sizeof(struct _objc_category), 0\n};\n"; -} - -// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or -/// class methods. -template<typename MethodIterator> -void RewriteObjCFragileABI::RewriteObjCMethodsMetaData(MethodIterator MethodBegin, - MethodIterator MethodEnd, - bool IsInstanceMethod, - StringRef prefix, - StringRef ClassName, - std::string &Result) { - if (MethodBegin == MethodEnd) return; - - if (!objc_impl_method) { - /* struct _objc_method { - SEL _cmd; - char *method_types; - void *_imp; - } - */ - Result += "\nstruct _objc_method {\n"; - Result += "\tSEL _cmd;\n"; - Result += "\tchar *method_types;\n"; - Result += "\tvoid *_imp;\n"; - Result += "};\n"; - - objc_impl_method = true; - } - - // Build _objc_method_list for class's methods if needed - - /* struct { - struct _objc_method_list *next_method; - int method_count; - struct _objc_method method_list[]; - } - */ - unsigned NumMethods = std::distance(MethodBegin, MethodEnd); - Result += "\nstatic struct {\n"; - Result += "\tstruct _objc_method_list *next_method;\n"; - Result += "\tint method_count;\n"; - Result += "\tstruct _objc_method method_list["; - Result += utostr(NumMethods); - Result += "];\n} _OBJC_"; - Result += prefix; - Result += IsInstanceMethod ? "INSTANCE" : "CLASS"; - Result += "_METHODS_"; - Result += ClassName; - Result += " __attribute__ ((used, section (\"__OBJC, __"; - Result += IsInstanceMethod ? "inst" : "cls"; - Result += "_meth\")))= "; - Result += "{\n\t0, " + utostr(NumMethods) + "\n"; - - Result += "\t,{{(SEL)\""; - Result += (*MethodBegin)->getSelector().getAsString().c_str(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\", (void *)"; - Result += MethodInternalNames[*MethodBegin]; - Result += "}\n"; - for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) { - Result += "\t ,{(SEL)\""; - Result += (*MethodBegin)->getSelector().getAsString().c_str(); - std::string MethodTypeString; - Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); - Result += "\", \""; - Result += MethodTypeString; - Result += "\", (void *)"; - Result += MethodInternalNames[*MethodBegin]; - Result += "}\n"; - } - Result += "\t }\n};\n"; -} - -Stmt *RewriteObjCFragileABI::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { - SourceRange OldRange = IV->getSourceRange(); - Expr *BaseExpr = IV->getBase(); - - // Rewrite the base, but without actually doing replaces. - { - DisableReplaceStmtScope S(*this); - BaseExpr = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(BaseExpr)); - IV->setBase(BaseExpr); - } - - ObjCIvarDecl *D = IV->getDecl(); - - Expr *Replacement = IV; - if (CurMethodDef) { - if (BaseExpr->getType()->isObjCObjectPointerType()) { - const ObjCInterfaceType *iFaceDecl = - dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType()); - assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null"); - // lookup which class implements the instance variable. - ObjCInterfaceDecl *clsDeclared = nullptr; - iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), - clsDeclared); - assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class"); - - // Synthesize an explicit cast to gain access to the ivar. - std::string RecName = clsDeclared->getIdentifier()->getName(); - RecName += "_IMPL"; - IdentifierInfo *II = &Context->Idents.get(RecName); - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - II); - assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); - QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, - CK_BitCast, - IV->getBase()); - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(OldRange.getBegin(), - OldRange.getEnd(), - castExpr); - if (IV->isFreeIvar() && - declaresSameEntity(CurMethodDef->getClassInterface(), iFaceDecl->getDecl())) { - MemberExpr *ME = new (Context) MemberExpr(PE, true, D, - IV->getLocation(), - D->getType(), - VK_LValue, OK_Ordinary); - Replacement = ME; - } else { - IV->setBase(PE); - } - } - } else { // we are outside a method. - assert(!IV->isFreeIvar() && "Cannot have a free standing ivar outside a method"); - - // Explicit ivar refs need to have a cast inserted. - // FIXME: consider sharing some of this code with the code above. - if (BaseExpr->getType()->isObjCObjectPointerType()) { - const ObjCInterfaceType *iFaceDecl = - dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType()); - // lookup which class implements the instance variable. - ObjCInterfaceDecl *clsDeclared = nullptr; - iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), - clsDeclared); - assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class"); - - // Synthesize an explicit cast to gain access to the ivar. - std::string RecName = clsDeclared->getIdentifier()->getName(); - RecName += "_IMPL"; - IdentifierInfo *II = &Context->Idents.get(RecName); - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - II); - assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); - QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, - CK_BitCast, - IV->getBase()); - // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(), - IV->getBase()->getLocEnd(), castExpr); - // Cannot delete IV->getBase(), since PE points to it. - // Replace the old base with the cast. This is important when doing - // embedded rewrites. For example, [newInv->_container addObject:0]. - IV->setBase(PE); - } - } - - ReplaceStmtWithRange(IV, Replacement, OldRange); - return Replacement; -} diff --git a/clang/lib/Rewrite/Frontend/RewriteTest.cpp b/clang/lib/Rewrite/Frontend/RewriteTest.cpp deleted file mode 100644 index 722c5e80b443..000000000000 --- a/clang/lib/Rewrite/Frontend/RewriteTest.cpp +++ /dev/null @@ -1,39 +0,0 @@ -//===--- RewriteTest.cpp - Rewriter playground ----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a testbed. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Frontend/Rewriters.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Rewrite/Core/TokenRewriter.h" -#include "llvm/Support/raw_ostream.h" - -void clang::DoRewriteTest(Preprocessor &PP, raw_ostream* OS) { - SourceManager &SM = PP.getSourceManager(); - const LangOptions &LangOpts = PP.getLangOpts(); - - TokenRewriter Rewriter(SM.getMainFileID(), SM, LangOpts); - - // Throw <i> </i> tags around comments. - for (TokenRewriter::token_iterator I = Rewriter.token_begin(), - E = Rewriter.token_end(); I != E; ++I) { - if (I->isNot(tok::comment)) continue; - - Rewriter.AddTokenBefore(I, "<i>"); - Rewriter.AddTokenAfter(I, "</i>"); - } - - - // Print out the output. - for (TokenRewriter::token_iterator I = Rewriter.token_begin(), - E = Rewriter.token_end(); I != E; ++I) - *OS << PP.getSpelling(*I); -} diff --git a/clang/lib/Rewrite/Core/HTMLRewrite.cpp b/clang/lib/Rewrite/HTMLRewrite.cpp index 275fbd0ebca2..275fbd0ebca2 100644 --- a/clang/lib/Rewrite/Core/HTMLRewrite.cpp +++ b/clang/lib/Rewrite/HTMLRewrite.cpp diff --git a/clang/lib/Rewrite/Makefile b/clang/lib/Rewrite/Makefile index 0be84d406405..5fef9b2c0d38 100644 --- a/clang/lib/Rewrite/Makefile +++ b/clang/lib/Rewrite/Makefile @@ -1,4 +1,4 @@ -##===- clang/lib/StaticAnalyzer/Makefile -------------------*- Makefile -*-===## +##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -6,9 +6,13 @@ # License. See LICENSE.TXT for details. # ##===----------------------------------------------------------------------===## +# +# This implements code transformation / rewriting facilities. +# +##===----------------------------------------------------------------------===## CLANG_LEVEL := ../.. -DIRS := Frontend -PARALLEL_DIRS := Core +LIBRARYNAME := clangRewrite include $(CLANG_LEVEL)/Makefile + diff --git a/clang/lib/Rewrite/Core/RewriteRope.cpp b/clang/lib/Rewrite/RewriteRope.cpp index ef8abfcadc03..ef8abfcadc03 100644 --- a/clang/lib/Rewrite/Core/RewriteRope.cpp +++ b/clang/lib/Rewrite/RewriteRope.cpp diff --git a/clang/lib/Rewrite/Core/Rewriter.cpp b/clang/lib/Rewrite/Rewriter.cpp index eab4ccfeadc3..eab4ccfeadc3 100644 --- a/clang/lib/Rewrite/Core/Rewriter.cpp +++ b/clang/lib/Rewrite/Rewriter.cpp diff --git a/clang/lib/Rewrite/Core/TokenRewriter.cpp b/clang/lib/Rewrite/TokenRewriter.cpp index 494defdedaa9..494defdedaa9 100644 --- a/clang/lib/Rewrite/Core/TokenRewriter.cpp +++ b/clang/lib/Rewrite/TokenRewriter.cpp |