diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Rewrite')
13 files changed, 38 insertions, 15207 deletions
diff --git a/contrib/llvm/tools/clang/lib/Rewrite/Core/DeltaTree.cpp b/contrib/llvm/tools/clang/lib/Rewrite/DeltaTree.cpp index 7a7f15b..352fab0 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/Core/DeltaTree.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/DeltaTree.cpp @@ -216,9 +216,9 @@ bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta, DoSplit(*InsertRes); if (InsertRes->Split.FileLoc > FileIndex) - InsertRes->LHS->DoInsertion(FileIndex, Delta, 0 /*can't fail*/); + InsertRes->LHS->DoInsertion(FileIndex, Delta, nullptr /*can't fail*/); else - InsertRes->RHS->DoInsertion(FileIndex, Delta, 0 /*can't fail*/); + InsertRes->RHS->DoInsertion(FileIndex, Delta, nullptr /*can't fail*/); return true; } diff --git a/contrib/llvm/tools/clang/lib/Rewrite/Frontend/FixItRewriter.cpp b/contrib/llvm/tools/clang/lib/Rewrite/Frontend/FixItRewriter.cpp deleted file mode 100644 index 8930c35..0000000 --- a/contrib/llvm/tools/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/ADT/OwningPtr.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include <cstdio> - -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) { } - - virtual void insert(SourceLocation loc, StringRef text) { - Rewrite.InsertText(loc, text); - } - virtual void replace(CharSourceRange range, StringRef text) { - 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; - OwningPtr<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_Binary)); - } - 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/contrib/llvm/tools/clang/lib/Rewrite/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Rewrite/Frontend/FrontendActions.cpp deleted file mode 100644 index e9ec388..0000000 --- a/contrib/llvm/tools/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/ADT/OwningPtr.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" - -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 0; -} - -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) { - 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) { - 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) { - 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(); - OwningPtr<FrontendAction> FixAction(new SyntaxOnlyAction()); - if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) { - OwningPtr<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(0); - CI.setFileManager(0); - } 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 0; -} - -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/contrib/llvm/tools/clang/lib/Rewrite/Frontend/HTMLPrint.cpp b/contrib/llvm/tools/clang/lib/Rewrite/Frontend/HTMLPrint.cpp deleted file mode 100644 index 79e4447..0000000 --- a/contrib/llvm/tools/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); - void HandleTranslationUnit(ASTContext &Ctx); - }; -} - -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/contrib/llvm/tools/clang/lib/Rewrite/Frontend/InclusionRewriter.cpp b/contrib/llvm/tools/clang/lib/Rewrite/Frontend/InclusionRewriter.cpp deleted file mode 100644 index 71ceb5f..0000000 --- a/contrib/llvm/tools/clang/lib/Rewrite/Frontend/InclusionRewriter.cpp +++ /dev/null @@ -1,550 +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: - virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType, - FileID PrevFID); - virtual void FileSkipped(const FileEntry &ParentFile, - const Token &FilenameTok, - SrcMgr::CharacteristicKind FileType); - virtual void InclusionDirective(SourceLocation HashLoc, - const Token &IncludeTok, - StringRef FileName, - bool IsAngled, - CharSourceRange FilenameRange, - const FileEntry *File, - StringRef SearchPath, - StringRef RelativePath, - const Module *Imported); - 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 = false); - 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(0), - 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 NULL; -} - -/// 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 == NULL) - 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); - Token DirectiveToken; - do { - DirectiveLex.LexFromRawLexer(DirectiveToken); - } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof)); - OS << "#if 0 /* expanded by -frewrite-includes */" << EOL; - OutputContentUpTo(FromFile, NextToWrite, - SM.getFileOffset(DirectiveToken.getLocation()) + DirectiveToken.getLength(), - EOL, Line); - 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, isAngled, 0, CurDir, - PP.getSourceManager().getFileEntryForID(FileId), 0, 0, 0, false); - - FileExists = File != 0; - 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 the start of a new file. - WriteLineInfo(FileName, 1, FileType, EOL, " 1"); - - if (SM.getFileIDSize(FileId) == 0) - return false; - - // The next byte to be copied from the source file - unsigned NextToWrite = 0; - int Line = 1; // The current input file line number. - - // Ignore UTF-8 BOM, otherwise it'd end up somewhere else than the start - // of the resulting file. - if (FromFile.getBuffer().startswith("\xEF\xBB\xBF")) - NextToWrite = 3; - - 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() != NULL) { - switch (RawToken.getIdentifierInfo()->getPPKeywordID()) { - case tok::pp_include: - case tok::pp_include_next: - case tok::pp_import: { - CommentOutDirective(RawLex, HashToken, FromFile, EOL, NextToWrite, - Line); - 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, 0, 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); - OS << '(' << (int) HasFile << ")/*"; - OutputContentUpTo(FromFile, NextToWrite, - SM.getFileOffset(RawToken.getLocation()) + - RawToken.getLength(), - EOL, Line); - 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); - // Ignore all pragmas, otherwise there will be warnings about unknown pragmas - // (because there's nothing to handle them). - PP.AddPragmaHandler(new EmptyPragmaHandler()); - // Ignore also all pragma in all namespaces created - // in Preprocessor::RegisterBuiltinPragmas(). - PP.AddPragmaHandler("GCC", new EmptyPragmaHandler()); - PP.AddPragmaHandler("clang", new EmptyPragmaHandler()); - - // 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/contrib/llvm/tools/clang/lib/Rewrite/Frontend/RewriteMacros.cpp b/contrib/llvm/tools/clang/lib/Rewrite/Frontend/RewriteMacros.cpp deleted file mode 100644 index 4f6a93f..0000000 --- a/contrib/llvm/tools/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/ADT/OwningPtr.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include <cstdio> - -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/contrib/llvm/tools/clang/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/contrib/llvm/tools/clang/lib/Rewrite/Frontend/RewriteModernObjC.cpp deleted file mode 100644 index ae33ac8..0000000 --- a/contrib/llvm/tools/clang/lib/Rewrite/Frontend/RewriteModernObjC.cpp +++ /dev/null @@ -1,7871 +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/OwningPtr.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" - -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. - virtual bool HandleTopLevelDecl(DeclGroupRef D) { - 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; - } - - virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) { - 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() {} - - virtual void HandleTranslationUnit(ASTContext &C); - - 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) { - 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, 0, 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); - - virtual void Initialize(ASTContext &context); - - // 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, 0, 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) != 0; - } - }; - -} - -void RewriteModernObjC::RewriteBlocksInFunctionProtoType(QualType funcType, - NamedDecl *D) { - if (const FunctionProtoType *fproto - = dyn_cast<FunctionProtoType>(funcType.IgnoreParens())) { - for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(), - E = fproto->arg_type_end(); I && (I != E); ++I) - 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 = 0; - MsgSendSuperFunctionDecl = 0; - MsgSendStretFunctionDecl = 0; - MsgSendSuperStretFunctionDecl = 0; - MsgSendFpretFunctionDecl = 0; - GetClassFunctionDecl = 0; - GetMetaClassFunctionDecl = 0; - GetSuperClassFunctionDecl = 0; - SelGetUidFunctionDecl = 0; - CFStringFunctionDecl = 0; - ConstantStringClassReference = 0; - NSStringRecord = 0; - CurMethodDef = 0; - CurFunctionDef = 0; - GlobalVarDecl = 0; - GlobalConstructionExp = 0; - SuperStructDecl = 0; - ProtocolTypeDecl = 0; - ConstantStringDecl = 0; - BcLabelCount = 0; - SuperConstructorFunctionDecl = 0; - NumObjCStringLiterals = 0; - PropParentMap = 0; - CurrentBody = 0; - 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, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get(D->getNameAsString()), - IvarT, 0, - /*BitWidth=*/0, /*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 = 0; - RewriteTypeIntoString(PD->getGetterMethodDecl()->getResultType(), 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->getNumArgs(); i != e; ++i) { - if (i) Getr += ", "; - std::string ParamStr = FT->getArgType(i).getAsString( - Context->getPrintingPolicy()); - Getr += ParamStr; - } - if (FT->isVariadic()) { - if (FT->getNumArgs()) 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 (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(), - E = CatDecl->prop_end(); I != E; ++I) - RewriteProperty(*I); - - for (ObjCCategoryDecl::instmeth_iterator - I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCCategoryDecl::classmeth_iterator - I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end(); - I != E; ++I) - 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 (ObjCProtocolDecl::instmeth_iterator - I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCProtocolDecl::classmeth_iterator - I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - - for (ObjCInterfaceDecl::prop_iterator I = PDecl->prop_begin(), - E = PDecl->prop_end(); I != E; ++I) - 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->getResultType().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 = 0; - ResultStr += "\nstatic "; - RewriteTypeIntoString(OMD->getResultType(), 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 (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), - E = OMD->param_end(); PI != E; ++PI) { - ParmVarDecl *PDecl = *PI; - 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->getNumArgs(); i != e; ++i) { - if (i) ResultStr += ", "; - std::string ParamStr = FT->getArgType(i).getAsString( - Context->getPrintingPolicy()); - ResultStr += ParamStr; - } - if (FT->isVariadic()) { - if (FT->getNumArgs()) 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 (ObjCCategoryImplDecl::instmeth_iterator - I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(), - E = IMD ? IMD->instmeth_end() : CID->instmeth_end(); - I != E; ++I) { - std::string ResultStr; - ObjCMethodDecl *OMD = *I; - 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 (ObjCCategoryImplDecl::classmeth_iterator - I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(), - E = IMD ? IMD->classmeth_end() : CID->classmeth_end(); - I != E; ++I) { - std::string ResultStr; - ObjCMethodDecl *OMD = *I; - 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 (ObjCCategoryImplDecl::propimpl_iterator - I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(), - E = IMD ? IMD->propimpl_end() : CID->propimpl_end(); - I != E; ++I) { - 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 (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(), - E = ClassDecl->prop_end(); I != E; ++I) - RewriteProperty(*I); - for (ObjCInterfaceDecl::instmeth_iterator - I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCInterfaceDecl::classmeth_iterator - I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end(); - I != E; ++I) - 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 = 0; - 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 = 0; - 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 = 0; - 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 = 0; - 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 0; -} - -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 0; -} - -/// 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 0; -} - -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 0; -} - -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 0; -} - -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 0; -} - -// 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 0; -} - -Stmt *RewriteModernObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) { - // Create a new string expression. - QualType StrType = Context->getPointerType(Context->CharTy); - std::string StrEncoding; - Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding); - Expr *Replacement = StringLiteral::Create(*Context, StrEncoding, - StringLiteral::Ascii, false, - StrType, SourceLocation()); - 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; - QualType argType = Context->getPointerType(Context->CharTy); - SelExprs.push_back(StringLiteral::Create(*Context, - Exp->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - 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, 0, 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 = 0, *endRef = 0; - 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 = 0; - 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->getResultType(); - } - 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 = 0, *endRef = 0; - 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->getNumArgs(); i++) { - if (needToScanForQualifiers(proto->getArgType(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 = 0, *endRef = 0; - 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, 0, - 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->getResultType(); - std::string FdStr = Type.getAsString(Context->getPrintingPolicy()); - FdStr += " "; - FdStr += FD->getName(); - FdStr += "("; - unsigned numArgs = proto->getNumArgs(); - for (unsigned i = 0; i < numArgs; i++) { - QualType ArgType = proto->getArgType(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, - 0, 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, 0, - 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, 0, - 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, 0, - 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, 0, - 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, 0, - 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, 0, - 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, 0, - 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, - 0, SC_Extern); -} - -Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { - 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, 0, 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, 0, 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; - QualType argType = Context->getPointerType(Context->CharTy); - - // 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(StringLiteral::Create(*Context, - clsName->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - 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(StringLiteral::Create(*Context, - BoxingMethod->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - 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 (ObjCMethodDecl::param_iterator PI = BoxingMethod->param_begin(), - E = BoxingMethod->param_end(); PI != E; ++PI) - 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->getResultType(), 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, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("arr"), - Context->getPointerType(Context->VoidPtrTy), 0, - /*BitWidth=*/0, /*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 argType = Context->getPointerType(Context->CharTy); - 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(StringLiteral::Create(*Context, - clsName->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - 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(StringLiteral::Create(*Context, - ArrayMethod->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - 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 (ObjCMethodDecl::param_iterator PI = ArrayMethod->param_begin(), - E = ArrayMethod->param_end(); PI != E; ++PI) - 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->getResultType(), 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, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("arr"), - Context->getPointerType(Context->VoidPtrTy), 0, - /*BitWidth=*/0, /*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 argType = Context->getPointerType(Context->CharTy); - 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(StringLiteral::Create(*Context, - clsName->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - 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(StringLiteral::Create(*Context, - DictMethod->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - 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 (ObjCMethodDecl::param_iterator PI = DictMethod->param_begin(), - E = DictMethod->param_end(); PI != E; ++PI) { - 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->getResultType(), 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(), 0, - FieldTypes[i], 0, - /*BitWidth=*/0, - /*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(), 0, - FieldTypes[i], 0, - /*BitWidth=*/0, - /*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, 0, - 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, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("s"), - returnType, 0, - /*BitWidth=*/0, /*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 = 0; - if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) { - QualType resultType = mDecl->getResultType(); - 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; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(StringLiteral::Create(*Context, - ClassDecl->getIdentifier()->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - // (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; - QualType argType = Context->getPointerType(Context->CharTy); - ObjCInterfaceDecl *Class - = Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface(); - IdentifierInfo *clsName = Class->getIdentifier(); - ClsExprs.push_back(StringLiteral::Create(*Context, - clsName->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - 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; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(StringLiteral::Create(*Context, - ClassDecl->getIdentifier()->getName(), - StringLiteral::Ascii, false, argType, - SourceLocation())); - // (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; - QualType argType = Context->getPointerType(Context->CharTy); - SelExprs.push_back(StringLiteral::Create(*Context, - Exp->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - 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 (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), - E = OMD->param_end(); PI != E; ++PI) { - 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->getResultType(), 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(), 0, - 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 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 (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; - 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 (EnumDecl::enumerator_iterator EC = ED->enumerator_begin(), - ECEnd = ED->enumerator_end(); EC != ECEnd; ++EC) { - 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 = 0; - 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(), - 0, /*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->getResultType(); - 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, 0, - PrintingPolicy(LangOpts)); - globalBuf += constructorExprBuf.str(); - globalBuf += ";\n"; - InsertText(FunLocStart, globalBuf); - GlobalConstructionExp = 0; - } - - 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->getResultType(); - bool modified = convertObjCTypeToCStyleType(Res); - - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I && (I != E); ++I) { - 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 = 0; - - 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 (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I && (I != E); ++I) { - 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, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("FuncPtr"), - Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*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, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("__forwarding"), - Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*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, 0, SourceLocation(), SourceLocation(), - &Context->Idents.get(Name), - Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*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 (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I != E; ++I) - 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 (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I != E; ++I) { - 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() != 0); - // 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, 0, 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, 0, - 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 (BlockDecl::capture_const_iterator ci = block->capture_begin(), - ce = block->capture_end(); ci != ce; ++ci) { - 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 == 0 && - "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 = 0; - // 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 = 0; - 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 (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; - 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 = 0; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = 0; - } - // This synthesizes and inserts the block "impl" struct, invoke function, - // and any copy/dispose helper functions. - InsertBlockLiteralsWithinFunction(FD); - RewriteLineDirective(D); - CurFunctionDef = 0; - } - 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 = 0; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = 0; - } - InsertBlockLiteralsWithinMethod(MD); - RewriteLineDirective(D); - CurMethodDef = 0; - } - 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 = 0; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = 0; - } - SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName()); - GlobalVarDecl = 0; - - // 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 untill all class and - // their extensions and implementations are seen. This is because, we - // cannot build grouping structs for bitfields untill 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 += " 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 += "#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 (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), - E = PDecl->protocol_end(); I != E; ++I) - RewriteObjCProtocolMetaData(*I, Result); - - // Construct method lists. - std::vector<ObjCMethodDecl *> InstanceMethods, ClassMethods; - std::vector<ObjCMethodDecl *> OptInstanceMethods, OptClassMethods; - for (ObjCProtocolDecl::instmeth_iterator - I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); - I != E; ++I) { - ObjCMethodDecl *MD = *I; - if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { - OptInstanceMethods.push_back(MD); - } else { - InstanceMethods.push_back(MD); - } - } - - for (ObjCProtocolDecl::classmeth_iterator - I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); - I != E; ++I) { - ObjCMethodDecl *MD = *I; - 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 - std::vector<ObjCProtocolDecl *> SuperProtocols; - for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), - E = PDecl->protocol_end(); I != E; ++I) - SuperProtocols.push_back(*I); - - 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. - std::vector<ObjCPropertyDecl *> ProtocolProperties; - for (ObjCContainerDecl::prop_iterator I = PDecl->prop_begin(), - E = PDecl->prop_end(); I != E; ++I) - ProtocolProperties.push_back(*I); - - Write_prop_list_t_initializer(*this, Context, Result, ProtocolProperties, - /* Container */0, - "_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->instmeth_begin(), IDecl->instmeth_end()); - - // If any of our property implementations have associated getters or - // setters, produce metadata for them as well. - for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), - PropEnd = IDecl->propimpl_end(); - Prop != PropEnd; ++Prop) { - 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->classmeth_begin(), IDecl->classmeth_end()); - - 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. - std::vector<ObjCPropertyDecl *> ClassProperties; - for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(), - E = CDecl->prop_end(); I != E; ++I) - ClassProperties.push_back(*I); - - 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, - 0, - 0, - 0, - "_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->instmeth_begin(), IDecl->instmeth_end()); - - // If any of our property implementations have associated getters or - // setters, produce metadata for them as well. - for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), - PropEnd = IDecl->propimpl_end(); - Prop != PropEnd; ++Prop) { - 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->classmeth_begin(), IDecl->classmeth_end()); - - 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 - std::vector<ObjCProtocolDecl *> RefedProtocols; - for (ObjCInterfaceDecl::protocol_iterator I = CDecl->protocol_begin(), - E = CDecl->protocol_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_CATEGORY_PROTOCOLS_$_", - FullCategoryName); - - // Protocol's property metadata. - std::vector<ObjCPropertyDecl *> ClassProperties; - for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(), - E = CDecl->prop_end(); I != E; ++I) - ClassProperties.push_back(*I); - - 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 = 0; - 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, 0, 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, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get(D->getNameAsString()), - IvarT, 0, - /*BitWidth=*/0, /*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, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get(D->getNameAsString()), - D->getType(), 0, - /*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/contrib/llvm/tools/clang/lib/Rewrite/Frontend/RewriteObjC.cpp b/contrib/llvm/tools/clang/lib/Rewrite/Frontend/RewriteObjC.cpp deleted file mode 100644 index 3dda2c5..0000000 --- a/contrib/llvm/tools/clang/lib/Rewrite/Frontend/RewriteObjC.cpp +++ /dev/null @@ -1,6011 +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/OwningPtr.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" - -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. - virtual bool HandleTopLevelDecl(DeclGroupRef D) { - 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() {} - - virtual void HandleTranslationUnit(ASTContext &C); - - 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) { - 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, 0, 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) = 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, 0, TInfo, - SourceLocation(), 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); - - // Rewriting metadata - template<typename MethodIterator> - void RewriteObjCMethodsMetaData(MethodIterator MethodBegin, - MethodIterator MethodEnd, - bool IsInstanceMethod, - StringRef prefix, - StringRef ClassName, - std::string &Result); - virtual void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol, - StringRef prefix, - StringRef ClassName, - std::string &Result); - virtual void RewriteObjCProtocolListMetaData( - const ObjCList<ObjCProtocolDecl> &Prots, - StringRef prefix, StringRef ClassName, std::string &Result); - virtual void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, - std::string &Result); - virtual void RewriteMetaDataIntoBuffer(std::string &Result); - virtual void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl, - std::string &Result); - - // Rewriting ivar - virtual void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, - std::string &Result); - virtual Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV); - }; -} - -void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType, - NamedDecl *D) { - if (const FunctionProtoType *fproto - = dyn_cast<FunctionProtoType>(funcType.IgnoreParens())) { - for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(), - E = fproto->arg_type_end(); I && (I != E); ++I) - 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 = 0; - MsgSendSuperFunctionDecl = 0; - MsgSendStretFunctionDecl = 0; - MsgSendSuperStretFunctionDecl = 0; - MsgSendFpretFunctionDecl = 0; - GetClassFunctionDecl = 0; - GetMetaClassFunctionDecl = 0; - GetSuperClassFunctionDecl = 0; - SelGetUidFunctionDecl = 0; - CFStringFunctionDecl = 0; - ConstantStringClassReference = 0; - NSStringRecord = 0; - CurMethodDef = 0; - CurFunctionDef = 0; - CurFunctionDeclToDeclareForBlock = 0; - GlobalVarDecl = 0; - SuperStructDecl = 0; - ProtocolTypeDecl = 0; - ConstantStringDecl = 0; - BcLabelCount = 0; - SuperConstructorFunctionDecl = 0; - NumObjCStringLiterals = 0; - PropParentMap = 0; - CurrentBody = 0; - 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 = 0; - RewriteTypeIntoString(PD->getGetterMethodDecl()->getResultType(), 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->getNumArgs(); i != e; ++i) { - if (i) Getr += ", "; - std::string ParamStr = FT->getArgType(i).getAsString( - Context->getPrintingPolicy()); - Getr += ParamStr; - } - if (FT->isVariadic()) { - if (FT->getNumArgs()) 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 (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(), - E = CatDecl->prop_end(); I != E; ++I) - RewriteProperty(*I); - - for (ObjCCategoryDecl::instmeth_iterator - I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCCategoryDecl::classmeth_iterator - I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end(); - I != E; ++I) - 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 (ObjCProtocolDecl::instmeth_iterator - I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCProtocolDecl::classmeth_iterator - I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - - for (ObjCInterfaceDecl::prop_iterator I = PDecl->prop_begin(), - E = PDecl->prop_end(); I != E; ++I) - 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->getResultType().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 = 0; - ResultStr += "\nstatic "; - RewriteTypeIntoString(OMD->getResultType(), 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 (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), - E = OMD->param_end(); PI != E; ++PI) { - ParmVarDecl *PDecl = *PI; - 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->getNumArgs(); i != e; ++i) { - if (i) ResultStr += ", "; - std::string ParamStr = FT->getArgType(i).getAsString( - Context->getPrintingPolicy()); - ResultStr += ParamStr; - } - if (FT->isVariadic()) { - if (FT->getNumArgs()) 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 (ObjCCategoryImplDecl::instmeth_iterator - I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(), - E = IMD ? IMD->instmeth_end() : CID->instmeth_end(); - I != E; ++I) { - std::string ResultStr; - ObjCMethodDecl *OMD = *I; - 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 (ObjCCategoryImplDecl::classmeth_iterator - I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(), - E = IMD ? IMD->classmeth_end() : CID->classmeth_end(); - I != E; ++I) { - std::string ResultStr; - ObjCMethodDecl *OMD = *I; - 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 (ObjCCategoryImplDecl::propimpl_iterator - I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(), - E = IMD ? IMD->propimpl_end() : CID->propimpl_end(); - I != E; ++I) { - 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 (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(), - E = ClassDecl->prop_end(); I != E; ++I) - RewriteProperty(*I); - for (ObjCInterfaceDecl::instmeth_iterator - I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDeclaration(*I); - for (ObjCInterfaceDecl::classmeth_iterator - I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end(); - I != E; ++I) - 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 = 0; - 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 = 0; - 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 = 0; - { - 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 = 0; - 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 0; -} - -/// 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 0; -} - -/// 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 0; -} - -/// 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); - syncExpr->printPretty(syncExprBuf, 0, 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 0; -} - -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 = 0; - 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 0; -} - -// 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 0; -} - -Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) { - // Create a new string expression. - QualType StrType = Context->getPointerType(Context->CharTy); - std::string StrEncoding; - Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding); - Expr *Replacement = StringLiteral::Create(*Context, StrEncoding, - StringLiteral::Ascii, false, - StrType, SourceLocation()); - 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; - QualType argType = Context->getPointerType(Context->CharTy); - SelExprs.push_back(StringLiteral::Create(*Context, - Exp->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - 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, 0, 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 = 0, *endRef = 0; - 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 = 0; - 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->getResultType(); - } - 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 = 0, *endRef = 0; - 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->getNumArgs(); i++) { - if (needToScanForQualifiers(proto->getArgType(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 = 0, *endRef = 0; - 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, 0, - 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->getResultType(); - std::string FdStr = Type.getAsString(Context->getPrintingPolicy()); - FdStr += " "; - FdStr += FD->getName(); - FdStr += "("; - unsigned numArgs = proto->getNumArgs(); - for (unsigned i = 0; i < numArgs; i++) { - QualType ArgType = proto->getArgType(i); - RewriteBlockPointerType(FdStr, ArgType); - if (i+1 < numArgs) - FdStr += ", "; - } - FdStr += ");\n"; - InsertText(FunLocStart, FdStr); - CurFunctionDeclToDeclareForBlock = 0; -} - -// 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, - 0, 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, 0, - 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, 0, - 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, 0, - 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, 0, - 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, 0, - 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, 0, - 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, 0, - 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, - 0, SC_Extern); -} - -Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { - 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, 0, 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, 0, 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(), 0, - FieldTypes[i], 0, - /*BitWidth=*/0, - /*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(), 0, - FieldTypes[i], 0, - /*BitWidth=*/0, - /*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->getResultType(), 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 = 0; - if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) { - QualType resultType = mDecl->getResultType(); - 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; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(StringLiteral::Create(*Context, - ClassDecl->getIdentifier()->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - 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; - QualType argType = Context->getPointerType(Context->CharTy); - ObjCInterfaceDecl *Class - = Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface(); - IdentifierInfo *clsName = Class->getIdentifier(); - ClsExprs.push_back(StringLiteral::Create(*Context, - clsName->getName(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - 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; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(StringLiteral::Create(*Context, - ClassDecl->getIdentifier()->getName(), - StringLiteral::Ascii, false, argType, - SourceLocation())); - 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; - QualType argType = Context->getPointerType(Context->CharTy); - SelExprs.push_back(StringLiteral::Create(*Context, - Exp->getSelector().getAsString(), - StringLiteral::Ascii, false, - argType, SourceLocation())); - 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 (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), - E = OMD->param_end(); PI != E; ++PI) { - 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->getResultType(), 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(), 0, - 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->getResultType(); - 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->getResultType(); - bool HasBlockType = convertBlockPointerToFunctionPointer(Res); - - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I && (I != E); ++I) { - 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 = 0; - - 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 (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I && (I != E); ++I) { - 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, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("FuncPtr"), - Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*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, 0, SourceLocation(), - SourceLocation(), - &Context->Idents.get("__forwarding"), - Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*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, 0, SourceLocation(), SourceLocation(), - &Context->Idents.get(Name), - Context->VoidPtrTy, 0, - /*BitWidth=*/0, /*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 (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I != E; ++I) - 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 (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I != E; ++I) { - 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() != 0); - 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, 0, 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, 0, - 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 (BlockDecl::capture_const_iterator ci = block->capture_begin(), - ce = block->capture_end(); ci != ce; ++ci) { - 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 = 0; - // 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 = 0; - 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 (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); - } - 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 (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; - 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 = 0; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = 0; - } - // This synthesizes and inserts the block "impl" struct, invoke function, - // and any copy/dispose helper functions. - InsertBlockLiteralsWithinFunction(FD); - CurFunctionDef = 0; - CurFunctionDeclToDeclareForBlock = 0; - } - 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 = 0; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = 0; - } - InsertBlockLiteralsWithinMethod(MD); - CurMethodDef = 0; - } - 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 = 0; - if (PropParentMap) { - delete PropParentMap; - PropParentMap = 0; - } - SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName()); - GlobalVarDecl = 0; - - // 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 (ObjCInterfaceDecl::ivar_iterator - IV = IDecl->ivar_begin(), IVEnd = IDecl->ivar_end(); - IV != IVEnd; ++IV) - 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->instmeth_begin(), IDecl->instmeth_end()); - - // If any of our property implementations have associated getters or - // setters, produce metadata for them as well. - for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), - PropEnd = IDecl->propimpl_end(); - Prop != PropEnd; ++Prop) { - 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 = 0; - 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->instmeth_begin(), IDecl->instmeth_end()); - - // If any of our property implementations have associated getters or - // setters, produce metadata for them as well. - for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), - PropEnd = IDecl->propimpl_end(); - Prop != PropEnd; ++Prop) { - 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 = 0; - 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 = 0; - 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/contrib/llvm/tools/clang/lib/Rewrite/Frontend/RewriteTest.cpp b/contrib/llvm/tools/clang/lib/Rewrite/Frontend/RewriteTest.cpp deleted file mode 100644 index 722c5e8..0000000 --- a/contrib/llvm/tools/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/contrib/llvm/tools/clang/lib/Rewrite/Core/HTMLRewrite.cpp b/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp index 4da00a8..275fbd0 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/Core/HTMLRewrite.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines the HTMLRewriter clas, which is used to translate the +// This file defines the HTMLRewriter class, which is used to translate the // text of a source file into prettified HTML. // //===----------------------------------------------------------------------===// @@ -17,11 +17,11 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Lex/TokenConcatenation.h" #include "clang/Rewrite/Core/Rewriter.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include <memory> using namespace clang; diff --git a/contrib/llvm/tools/clang/lib/Rewrite/Core/RewriteRope.cpp b/contrib/llvm/tools/clang/lib/Rewrite/RewriteRope.cpp index fe7aa2d..ef8abfc 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/Core/RewriteRope.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/RewriteRope.cpp @@ -146,7 +146,7 @@ namespace { RopePieceBTreeLeaf **PrevLeaf, *NextLeaf; public: RopePieceBTreeLeaf() : RopePieceBTreeNode(true), NumPieces(0), - PrevLeaf(0), NextLeaf(0) {} + PrevLeaf(nullptr), NextLeaf(nullptr) {} ~RopePieceBTreeLeaf() { if (PrevLeaf || NextLeaf) removeFromLeafInOrder(); @@ -171,7 +171,7 @@ namespace { const RopePieceBTreeLeaf *getNextLeafInOrder() const { return NextLeaf; } void insertAfterLeafInOrder(RopePieceBTreeLeaf *Node) { - assert(PrevLeaf == 0 && NextLeaf == 0 && "Already in ordering"); + assert(!PrevLeaf && !NextLeaf && "Already in ordering"); NextLeaf = Node->NextLeaf; if (NextLeaf) @@ -186,7 +186,7 @@ namespace { if (NextLeaf) NextLeaf->PrevLeaf = PrevLeaf; } else if (NextLeaf) { - NextLeaf->PrevLeaf = 0; + NextLeaf->PrevLeaf = nullptr; } } @@ -236,7 +236,7 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::split(unsigned Offset) { // specified offset so find it. if (Offset == 0 || Offset == size()) { // Fastpath for a common case. There is already a splitpoint at the end. - return 0; + return nullptr; } // Find the piece that this offset lands in. @@ -250,7 +250,7 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::split(unsigned Offset) { // If there is already a split point at the specified offset, just return // success. if (PieceOffs == Offset) - return 0; + return nullptr; // Otherwise, we need to split piece 'i' at Offset-PieceOffs. Convert Offset // to being Piece relative. @@ -296,7 +296,7 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::insert(unsigned Offset, Pieces[i] = R; ++NumPieces; Size += R.size(); - return 0; + return nullptr; } // Otherwise, if this is leaf is full, split it in two halves. Since this @@ -470,7 +470,7 @@ namespace { RopePieceBTreeNode *RopePieceBTreeInterior::split(unsigned Offset) { // Figure out which child to split. if (Offset == 0 || Offset == size()) - return 0; // If we have an exact offset, we're already split. + return nullptr; // If we have an exact offset, we're already split. unsigned ChildOffset = 0; unsigned i = 0; @@ -479,12 +479,12 @@ RopePieceBTreeNode *RopePieceBTreeInterior::split(unsigned Offset) { // If already split there, we're done. if (ChildOffset == Offset) - return 0; + return nullptr; // Otherwise, recursively split the child. if (RopePieceBTreeNode *RHS = getChild(i)->split(Offset-ChildOffset)) return HandleChildPiece(i, RHS); - return 0; // Done! + return nullptr; // Done! } /// insert - Insert the specified ropepiece into this tree node at the @@ -515,7 +515,7 @@ RopePieceBTreeNode *RopePieceBTreeInterior::insert(unsigned Offset, if (RopePieceBTreeNode *RHS = getChild(i)->insert(Offset-ChildOffs, R)) return HandleChildPiece(i, RHS); - return 0; + return nullptr; } /// HandleChildPiece - A child propagated an insertion result up to us. @@ -531,7 +531,7 @@ RopePieceBTreeInterior::HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS) { (getNumChildren()-i-1)*sizeof(Children[0])); Children[i+1] = RHS; ++NumChildren; - return 0; + return nullptr; } // Okay, this node is full. Split it in half, moving WidthFactor children to @@ -678,10 +678,10 @@ RopePieceBTreeIterator::RopePieceBTreeIterator(const void *n) { while (CurNode && getCN(CurNode)->getNumPieces() == 0) CurNode = getCN(CurNode)->getNextLeafInOrder(); - if (CurNode != 0) + if (CurNode) CurPiece = &getCN(CurNode)->getPiece(0); else // Empty tree, this is an end() iterator. - CurPiece = 0; + CurPiece = nullptr; CurChar = 0; } @@ -697,10 +697,10 @@ void RopePieceBTreeIterator::MoveToNextPiece() { CurNode = getCN(CurNode)->getNextLeafInOrder(); while (CurNode && getCN(CurNode)->getNumPieces() == 0); - if (CurNode != 0) + if (CurNode) CurPiece = &getCN(CurNode)->getPiece(0); else // Hit end(). - CurPiece = 0; + CurPiece = nullptr; CurChar = 0; } @@ -788,9 +788,8 @@ RopePiece RewriteRope::MakeRopeString(const char *Start, const char *End) { // Otherwise, this was a small request but we just don't have space for it // Make a new chunk and share it with later allocations. - // If we had an old allocation, drop our reference to it. - if (AllocBuffer && --AllocBuffer->RefCount == 0) - delete [] (char*)AllocBuffer; + if (AllocBuffer) + AllocBuffer->dropRef(); unsigned AllocSize = offsetof(RopeRefCountString, Data) + AllocChunkSize; AllocBuffer = reinterpret_cast<RopeRefCountString *>(new char[AllocSize]); diff --git a/contrib/llvm/tools/clang/lib/Rewrite/Core/Rewriter.cpp b/contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp index afb1080..eab4ccf 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/Core/Rewriter.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp @@ -21,13 +21,17 @@ #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" using namespace clang; raw_ostream &RewriteBuffer::write(raw_ostream &os) const { - // FIXME: eliminate the copy by writing out each chunk at a time - os << std::string(begin(), end()); + // Walk RewriteRope chunks efficiently using MoveToNextPiece() instead of the + // character iterator. + for (RopePieceBTreeIterator I = begin(), E = end(); I != E; + I.MoveToNextPiece()) + os << I.piece(); return os; } @@ -328,6 +332,8 @@ bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) { /// printer to generate the replacement code. This returns true if the input /// could not be rewritten, or false if successful. bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) { + assert(From != nullptr && To != nullptr && "Expected non-null Stmt's"); + // Measaure the old text. int Size = getRangeSize(From->getSourceRange()); if (Size == -1) @@ -336,7 +342,7 @@ bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) { // Get the new text. std::string SStr; llvm::raw_string_ostream S(SStr); - To->printPretty(S, 0, PrintingPolicy(*LangOpts)); + To->printPretty(S, nullptr, PrintingPolicy(*LangOpts)); const std::string &Str = S.str(); ReplaceText(From->getLocStart(), Size, Str); @@ -344,9 +350,10 @@ bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) { } std::string Rewriter::ConvertToString(Stmt *From) { + assert(From != nullptr && "Expected non-null Stmt"); std::string SStr; llvm::raw_string_ostream S(SStr); - From->printPretty(S, 0, PrintingPolicy(*LangOpts)); + From->printPretty(S, nullptr, PrintingPolicy(*LangOpts)); return S.str(); } @@ -446,30 +453,29 @@ public: if (!ok()) return; FileStream->flush(); -#ifdef _WIN32 +#ifdef LLVM_ON_WIN32 // Win32 does not allow rename/removing opened files. FileStream.reset(); #endif - if (llvm::error_code ec = - llvm::sys::fs::rename(TempFilename.str(), Filename)) { + if (std::error_code ec = + llvm::sys::fs::rename(TempFilename.str(), Filename)) { AllWritten = false; Diagnostics.Report(clang::diag::err_unable_to_rename_temp) << TempFilename << Filename << ec.message(); - bool existed; // If the remove fails, there's not a lot we can do - this is already an // error. - llvm::sys::fs::remove(TempFilename.str(), existed); + llvm::sys::fs::remove(TempFilename.str()); } } - bool ok() { return FileStream.isValid(); } + bool ok() { return (bool)FileStream; } raw_ostream &getStream() { return *FileStream; } private: DiagnosticsEngine &Diagnostics; StringRef Filename; SmallString<128> TempFilename; - OwningPtr<llvm::raw_fd_ostream> FileStream; + std::unique_ptr<llvm::raw_fd_ostream> FileStream; bool &AllWritten; }; } // end anonymous namespace diff --git a/contrib/llvm/tools/clang/lib/Rewrite/Core/TokenRewriter.cpp b/contrib/llvm/tools/clang/lib/Rewrite/TokenRewriter.cpp index 494defd..494defd 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/Core/TokenRewriter.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/TokenRewriter.cpp |