diff options
author | Ted Kremenek <kremenek@apple.com> | 2012-03-06 20:06:33 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2012-03-06 20:06:33 +0000 |
commit | f7639e1b4a6c8cbf69c0005c6173ac863735b572 (patch) | |
tree | ec10ddb85eb9803b67b1053bcac26e0050810ff3 | |
parent | d151dde0e6673a15e9bf0b5f328df461dfd8cae9 (diff) | |
download | bcm5719-llvm-f7639e1b4a6c8cbf69c0005c6173ac863735b572.tar.gz bcm5719-llvm-f7639e1b4a6c8cbf69c0005c6173ac863735b572.zip |
Add new code migrator support for migrating existing Objective-C code to use
the new Objective-C NSArray/NSDictionary/NSNumber literal syntax.
This introduces a new library, libEdit, which provides a new way to support
migration of code that improves on the original ARC migrator. We now believe
that most of its functionality can be refactored into the existing libraries,
and thus this new library may shortly disappear.
llvm-svn: 152141
64 files changed, 3748 insertions, 99 deletions
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 746490be881..fd7a9f3a015 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -3983,6 +3983,20 @@ typedef void *CXRemapping; CINDEX_LINKAGE CXRemapping clang_getRemappings(const char *path); /** + * \brief Retrieve a remapping. + * + * \param filePaths pointer to an array of file paths containing remapping info. + * + * \param numFiles number of file paths. + * + * \returns the requested remapping. This remapping must be freed + * via a call to \c clang_remap_dispose(). Can return NULL if an error occurred. + */ +CINDEX_LINKAGE +CXRemapping clang_getRemappingsFromFileList(const char **filePaths, + unsigned numFiles); + +/** * \brief Determine the number of remappings. */ CINDEX_LINKAGE unsigned clang_remap_getNumFiles(CXRemapping); diff --git a/clang/include/clang/ARCMigrate/ARCMT.h b/clang/include/clang/ARCMigrate/ARCMT.h index 738a00dcd01..86a6cbb22aa 100644 --- a/clang/include/clang/ARCMigrate/ARCMT.h +++ b/clang/include/clang/ARCMigrate/ARCMT.h @@ -76,6 +76,15 @@ bool getFileRemappings(std::vector<std::pair<std::string,std::string> > &remap, StringRef outputDir, DiagnosticConsumer *DiagClient); +/// \brief Get the set of file remappings from a list of files with remapping +/// info. +/// +/// \returns false if no error is produced, true otherwise. +bool getFileRemappingsFromFileList( + std::vector<std::pair<std::string,std::string> > &remap, + ArrayRef<StringRef> remapFiles, + DiagnosticConsumer *DiagClient); + typedef void (*TransformFn)(MigrationPass &pass); std::vector<TransformFn> getAllTransformations(LangOptions::GCMode OrigGCMode, diff --git a/clang/include/clang/ARCMigrate/ARCMTActions.h b/clang/include/clang/ARCMigrate/ARCMTActions.h index 4eac4facdd8..e0752521378 100644 --- a/clang/include/clang/ARCMigrate/ARCMTActions.h +++ b/clang/include/clang/ARCMigrate/ARCMTActions.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H #include "clang/Frontend/FrontendAction.h" +#include "clang/ARCMigrate/FileRemapper.h" #include "llvm/ADT/OwningPtr.h" namespace clang { @@ -32,6 +33,14 @@ public: ModifyAction(FrontendAction *WrappedAction); }; +class MigrateSourceAction : public ASTFrontendAction { + FileRemapper Remapper; +protected: + virtual bool BeginInvocation(CompilerInstance &CI); + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); +}; + class MigrateAction : public WrapperFrontendAction { std::string MigrateDir; std::string PlistOut; @@ -45,6 +54,23 @@ public: bool emitPremigrationARCErrors); }; +/// \brief Migrates to modern ObjC syntax. +class ObjCMigrateAction : public WrapperFrontendAction { + std::string MigrateDir; + bool MigrateLiterals; + bool MigrateSubscripting; + FileRemapper Remapper; + CompilerInstance *CompInst; +public: + ObjCMigrateAction(FrontendAction *WrappedAction, StringRef migrateDir, + bool migrateLiterals, + bool migrateSubscripting); + +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,StringRef InFile); + virtual bool BeginInvocation(CompilerInstance &CI); +}; + } } diff --git a/clang/include/clang/ARCMigrate/FileRemapper.h b/clang/include/clang/ARCMigrate/FileRemapper.h index a451988f933..fe7cfadb497 100644 --- a/clang/include/clang/ARCMigrate/FileRemapper.h +++ b/clang/include/clang/ARCMigrate/FileRemapper.h @@ -24,7 +24,7 @@ namespace clang { class FileManager; class FileEntry; class DiagnosticsEngine; - class CompilerInvocation; + class PreprocessorOptions; namespace arcmt { @@ -44,7 +44,10 @@ public: bool initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag, bool ignoreIfFilesChanged); + bool initFromFile(StringRef filePath, DiagnosticsEngine &Diag, + bool ignoreIfFilesChanged); bool flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag); + bool flushToFile(StringRef outputPath, DiagnosticsEngine &Diag); bool overwriteOriginal(DiagnosticsEngine &Diag, StringRef outputDir = StringRef()); @@ -52,9 +55,9 @@ public: void remap(StringRef filePath, llvm::MemoryBuffer *memBuf); void remap(StringRef filePath, StringRef newPath); - void applyMappings(CompilerInvocation &CI) const; + void applyMappings(PreprocessorOptions &PPOpts) const; - void transferMappingsAndClear(CompilerInvocation &CI); + void transferMappingsAndClear(PreprocessorOptions &PPOpts); void clear(StringRef outputDir = StringRef()); diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index 3e54b4352b6..2b71d445cc9 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -50,13 +50,19 @@ public: /// insertion hint. CharSourceRange RemoveRange; + /// \brief Code in the specific range that should be inserted in the insertion + /// location. + CharSourceRange InsertFromRange; + /// \brief The actual code to insert at the insertion location, as a /// string. std::string CodeToInsert; + bool BeforePreviousInsertions; + /// \brief Empty code modification hint, indicating that no code /// modification is known. - FixItHint() : RemoveRange() { } + FixItHint() : BeforePreviousInsertions(false) { } bool isNull() const { return !RemoveRange.isValid(); @@ -65,11 +71,26 @@ public: /// \brief Create a code modification hint that inserts the given /// code string at a specific location. static FixItHint CreateInsertion(SourceLocation InsertionLoc, - StringRef Code) { + StringRef Code, + bool BeforePreviousInsertions = false) { FixItHint Hint; Hint.RemoveRange = CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false); Hint.CodeToInsert = Code; + Hint.BeforePreviousInsertions = BeforePreviousInsertions; + return Hint; + } + + /// \brief Create a code modification hint that inserts the given + /// code from \arg FromRange at a specific location. + static FixItHint CreateInsertionFromRange(SourceLocation InsertionLoc, + CharSourceRange FromRange, + bool BeforePreviousInsertions = false) { + FixItHint Hint; + Hint.RemoveRange = + CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false); + Hint.InsertFromRange = FromRange; + Hint.BeforePreviousInsertions = BeforePreviousInsertions; return Hint; } diff --git a/clang/include/clang/Driver/Action.h b/clang/include/clang/Driver/Action.h index 41ce4d92c40..6e317a0726b 100644 --- a/clang/include/clang/Driver/Action.h +++ b/clang/include/clang/Driver/Action.h @@ -39,6 +39,7 @@ public: PreprocessJobClass, PrecompileJobClass, AnalyzeJobClass, + MigrateJobClass, CompileJobClass, AssembleJobClass, LinkJobClass, @@ -171,6 +172,17 @@ public: static bool classof(const AnalyzeJobAction *) { return true; } }; +class MigrateJobAction : public JobAction { + virtual void anchor(); +public: + MigrateJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == MigrateJobClass; + } + static bool classof(const MigrateJobAction *) { return true; } +}; + class CompileJobAction : public JobAction { virtual void anchor(); public: diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td index 93e63dee61a..2fe4eba2057 100644 --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -433,21 +433,28 @@ def rewrite_objc : Flag<"-rewrite-objc">, HelpText<"Rewrite ObjC into C (code rewriter example)">; def rewrite_macros : Flag<"-rewrite-macros">, HelpText<"Expand macros without full preprocessing">; +def migrate : Flag<"-migrate">, + HelpText<"Migrate source code">; } +def mt_migrate_directory : Separate<"-mt-migrate-directory">, + HelpText<"Directory for temporary files produced during ARC or ObjC migration">; def arcmt_check : Flag<"-arcmt-check">, HelpText<"Check for ARC migration issues that need manual handling">; def arcmt_modify : Flag<"-arcmt-modify">, HelpText<"Apply modifications to files to conform to ARC">; def arcmt_migrate : Flag<"-arcmt-migrate">, HelpText<"Apply modifications and produces temporary files that conform to ARC">; -def arcmt_migrate_directory : Separate<"-arcmt-migrate-directory">, - HelpText<"Directory for temporary files produced during ARC migration">; def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">, HelpText<"Output path for the plist report">; def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">, HelpText<"Emit ARC errors even if the migrator can fix them">; +def objcmt_migrate_literals : Flag<"-objcmt-migrate-literals">, + HelpText<"Enable migration to modern ObjC literals">; +def objcmt_migrate_subscripting : Flag<"-objcmt-migrate-subscripting">, + HelpText<"Enable migration to modern ObjC subscripting">; + def working_directory : JoinedOrSeparate<"-working-directory">, HelpText<"Resolve file paths relative to the specified directory">; def working_directory_EQ : Joined<"-working-directory=">, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index b269ddb045e..51c5e020e1b 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -118,13 +118,21 @@ def ccc_arrmt_check : Flag<"-ccc-arrmt-check">, Alias<ccc_arcmt_check>; def ccc_arrmt_modify : Flag<"-ccc-arrmt-modify">, Alias<ccc_arcmt_modify>; def ccc_arcmt_migrate : Separate<"-ccc-arcmt-migrate">, CCCDriverOpt, HelpText<"Apply modifications and produces temporary files that conform to ARC">; -def ccc_arcmt_migrate_EQ : Joined<"-ccc-arcmt-migrate=">, CCCDriverOpt, - Alias<ccc_arcmt_migrate>; def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">, HelpText<"Output path for the plist report">; def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">, HelpText<"Emit ARC errors even if the migrator can fix them">; +def _migrate : Flag<"--migrate">, Flags<[DriverOption]>, + HelpText<"Run the migrator">; +def ccc_objcmt_migrate : Separate<"-ccc-objcmt-migrate">, CCCDriverOpt, + HelpText<"Apply modifications and produces temporary files to migrate to " + "modern ObjC syntax">; +def objcmt_migrate_literals : Flag<"-objcmt-migrate-literals">, + HelpText<"Enable migration to modern ObjC literals">; +def objcmt_migrate_subscripting : Flag<"-objcmt-migrate-subscripting">, + HelpText<"Enable migration to modern ObjC subscripting">; + // Make sure all other -ccc- options are rejected. def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>; diff --git a/clang/include/clang/Driver/Types.def b/clang/include/clang/Driver/Types.def index 8449d639e69..bba888ca4a7 100644 --- a/clang/include/clang/Driver/Types.def +++ b/clang/include/clang/Driver/Types.def @@ -82,6 +82,7 @@ TYPE("lto-bc", LTO_BC, INVALID, "o", "") TYPE("ast", AST, INVALID, "ast", "u") TYPE("plist", Plist, INVALID, "plist", "") TYPE("rewritten-objc", RewrittenObjC,INVALID, "cpp", "") +TYPE("remap", Remap, INVALID, "remap", "") TYPE("precompiled-header", PCH, INVALID, "gch", "A") TYPE("object", Object, INVALID, "o", "") TYPE("treelang", Treelang, INVALID, 0, "u") diff --git a/clang/include/clang/Edit/Commit.h b/clang/include/clang/Edit/Commit.h new file mode 100644 index 00000000000..aaf6b183847 --- /dev/null +++ b/clang/include/clang/Edit/Commit.h @@ -0,0 +1,140 @@ +//===----- Commit.h - A unit of edits ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EDIT_COMMIT_H +#define LLVM_CLANG_EDIT_COMMIT_H + +#include "clang/Edit/FileOffset.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class LangOptions; + class PreprocessingRecord; + +namespace edit { + class EditedSource; + +class Commit { +public: + enum EditKind { + Act_Insert, + Act_InsertFromRange, + Act_Remove + }; + + struct Edit { + EditKind Kind; + StringRef Text; + SourceLocation OrigLoc; + FileOffset Offset; + FileOffset InsertFromRangeOffs; + unsigned Length; + bool BeforePrev; + + SourceLocation getFileLocation(SourceManager &SM) const; + CharSourceRange getFileRange(SourceManager &SM) const; + CharSourceRange getInsertFromRange(SourceManager &SM) const; + }; + +private: + const SourceManager &SourceMgr; + const LangOptions &LangOpts; + const PreprocessingRecord *PPRec; + EditedSource *Editor; + + bool IsCommitable; + SmallVector<Edit, 8> CachedEdits; + +public: + explicit Commit(EditedSource &Editor); + Commit(const SourceManager &SM, const LangOptions &LangOpts, + const PreprocessingRecord *PPRec = 0) + : SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec), Editor(0), + IsCommitable(true) { } + + bool isCommitable() const { return IsCommitable; } + + bool insert(SourceLocation loc, StringRef text, bool afterToken = false, + bool beforePreviousInsertions = false); + bool insertAfterToken(SourceLocation loc, StringRef text, + bool beforePreviousInsertions = false) { + return insert(loc, text, /*afterToken=*/true, beforePreviousInsertions); + } + bool insertBefore(SourceLocation loc, StringRef text) { + return insert(loc, text, /*afterToken=*/false, + /*beforePreviousInsertions=*/true); + } + bool insertFromRange(SourceLocation loc, CharSourceRange range, + bool afterToken = false, + bool beforePreviousInsertions = false); + bool insertWrap(StringRef before, CharSourceRange range, StringRef after); + + bool remove(CharSourceRange range); + + bool replace(CharSourceRange range, StringRef text); + bool replaceWithInner(CharSourceRange range, CharSourceRange innerRange); + bool replaceText(SourceLocation loc, StringRef text, + StringRef replacementText); + + bool insertFromRange(SourceLocation loc, SourceRange TokenRange, + bool afterToken = false, + bool beforePreviousInsertions = false) { + return insertFromRange(loc, CharSourceRange::getTokenRange(TokenRange), + afterToken, beforePreviousInsertions); + } + bool insertWrap(StringRef before, SourceRange TokenRange, StringRef after) { + return insertWrap(before, CharSourceRange::getTokenRange(TokenRange), after); + } + bool remove(SourceRange TokenRange) { + return remove(CharSourceRange::getTokenRange(TokenRange)); + } + bool replace(SourceRange TokenRange, StringRef text) { + return replace(CharSourceRange::getTokenRange(TokenRange), text); + } + bool replaceWithInner(SourceRange TokenRange, SourceRange TokenInnerRange) { + return replaceWithInner(CharSourceRange::getTokenRange(TokenRange), + CharSourceRange::getTokenRange(TokenInnerRange)); + } + + typedef SmallVector<Edit, 8>::const_iterator edit_iterator; + edit_iterator edit_begin() const { return CachedEdits.begin(); } + edit_iterator edit_end() const { return CachedEdits.end(); } + +private: + void addInsert(SourceLocation OrigLoc, + FileOffset Offs, StringRef text, bool beforePreviousInsertions); + void addInsertFromRange(SourceLocation OrigLoc, FileOffset Offs, + FileOffset RangeOffs, unsigned RangeLen, + bool beforePreviousInsertions); + void addRemove(SourceLocation OrigLoc, FileOffset Offs, unsigned Len); + + bool canInsert(SourceLocation loc, FileOffset &Offset); + bool canInsertAfterToken(SourceLocation loc, FileOffset &Offset, + SourceLocation &AfterLoc); + bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs); + bool canRemoveRange(CharSourceRange range, FileOffset &Offs, unsigned &Len); + bool canReplaceText(SourceLocation loc, StringRef text, + FileOffset &Offs, unsigned &Len); + + void commitInsert(FileOffset offset, StringRef text, + bool beforePreviousInsertions); + void commitRemove(FileOffset offset, unsigned length); + + bool isAtStartOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroBegin = 0) const; + bool isAtEndOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroEnd = 0) const; +}; + +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Edit/EditedSource.h b/clang/include/clang/Edit/EditedSource.h new file mode 100644 index 00000000000..273921cee5e --- /dev/null +++ b/clang/include/clang/Edit/EditedSource.h @@ -0,0 +1,87 @@ +//===----- EditedSource.h - Collection of source edits ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EDIT_EDITEDSOURCE_H +#define LLVM_CLANG_EDIT_EDITEDSOURCE_H + +#include "clang/Edit/FileOffset.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" +#include <map> + +namespace clang { + class LangOptions; + class PreprocessingRecord; + +namespace edit { + class Commit; + class EditsReceiver; + +class EditedSource { + const SourceManager &SourceMgr; + const LangOptions &LangOpts; + const PreprocessingRecord *PPRec; + + struct FileEdit { + StringRef Text; + unsigned RemoveLen; + + FileEdit() : RemoveLen(0) {} + }; + + typedef std::map<FileOffset, FileEdit> FileEditsTy; + FileEditsTy FileEdits; + + llvm::DenseMap<unsigned, SourceLocation> ExpansionToArgMap; + + llvm::BumpPtrAllocator StrAlloc; + +public: + EditedSource(const SourceManager &SM, const LangOptions &LangOpts, + const PreprocessingRecord *PPRec = 0) + : SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec), + StrAlloc(/*size=*/512) { } + + const SourceManager &getSourceManager() const { return SourceMgr; } + const LangOptions &getLangOptions() const { return LangOpts; } + const PreprocessingRecord *getPreprocessingRecord() const { return PPRec; } + + bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs); + + bool commit(const Commit &commit); + + void applyRewrites(EditsReceiver &receiver); + void clearRewrites(); + + StringRef copyString(StringRef str) { + char *buf = StrAlloc.Allocate<char>(str.size()); + std::uninitialized_copy(str.begin(), str.end(), buf); + return StringRef(buf, str.size()); + } + StringRef copyString(const Twine &twine); + +private: + bool commitInsert(SourceLocation OrigLoc, FileOffset Offs, StringRef text, + bool beforePreviousInsertions); + bool commitInsertFromRange(SourceLocation OrigLoc, FileOffset Offs, + FileOffset InsertFromRangeOffs, unsigned Len, + bool beforePreviousInsertions); + void commitRemove(SourceLocation OrigLoc, FileOffset BeginOffs, unsigned Len); + + StringRef getSourceText(FileOffset BeginOffs, FileOffset EndOffs, + bool &Invalid); + FileEditsTy::iterator getActionForOffset(FileOffset Offs); +}; + +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Edit/EditsReceiver.h b/clang/include/clang/Edit/EditsReceiver.h new file mode 100644 index 00000000000..600ac28ea92 --- /dev/null +++ b/clang/include/clang/Edit/EditsReceiver.h @@ -0,0 +1,35 @@ +//===----- EditedSource.h - Collection of source edits ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EDIT_EDITSRECEIVER_H +#define LLVM_CLANG_EDIT_EDITSRECEIVER_H + +#include "clang/Basic/LLVM.h" + +namespace clang { + class SourceLocation; + class CharSourceRange; + +namespace edit { + +class EditsReceiver { +public: + virtual ~EditsReceiver() { } + + virtual void insert(SourceLocation loc, StringRef text) = 0; + virtual void replace(CharSourceRange range, StringRef text) = 0; + /// \brief By default it calls replace with an empty string. + virtual void remove(CharSourceRange range); +}; + +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Edit/FileOffset.h b/clang/include/clang/Edit/FileOffset.h new file mode 100644 index 00000000000..675ad18fcd3 --- /dev/null +++ b/clang/include/clang/Edit/FileOffset.h @@ -0,0 +1,65 @@ +//===----- FileOffset.h - Offset in a file ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EDIT_FILEOFFSET_H +#define LLVM_CLANG_EDIT_FILEOFFSET_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + +namespace edit { + +class FileOffset { + FileID FID; + unsigned Offs; +public: + FileOffset() : Offs(0) { } + FileOffset(FileID fid, unsigned offs) : FID(fid), Offs(offs) { } + + bool isInvalid() const { return FID.isInvalid(); } + + FileID getFID() const { return FID; } + unsigned getOffset() const { return Offs; } + + FileOffset getWithOffset(unsigned offset) const { + FileOffset NewOffs = *this; + NewOffs.Offs += offset; + return NewOffs; + } + + friend bool operator==(FileOffset LHS, FileOffset RHS) { + return LHS.FID == RHS.FID && LHS.Offs == RHS.Offs; + } + friend bool operator!=(FileOffset LHS, FileOffset RHS) { + return !(LHS == RHS); + } + friend bool operator<(FileOffset LHS, FileOffset RHS) { + if (LHS.FID != RHS.FID) + return LHS.FID < RHS.FID; + return LHS.Offs < RHS.Offs; + } + friend bool operator>(FileOffset LHS, FileOffset RHS) { + if (LHS.FID != RHS.FID) + return LHS.FID > RHS.FID; + return LHS.Offs > RHS.Offs; + } + friend bool operator>=(FileOffset LHS, FileOffset RHS) { + return LHS > RHS || LHS == RHS; + } + friend bool operator<=(FileOffset LHS, FileOffset RHS) { + return LHS < RHS || LHS == RHS; + } +}; + +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Edit/Rewriters.h b/clang/include/clang/Edit/Rewriters.h new file mode 100644 index 00000000000..aa7a5b23202 --- /dev/null +++ b/clang/include/clang/Edit/Rewriters.h @@ -0,0 +1,33 @@ +//===--- Rewriters.h - Rewritings ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EDIT_REWRITERS_H +#define LLVM_CLANG_EDIT_REWRITERS_H + +namespace clang { + class ObjCMessageExpr; + class NSAPI; + +namespace edit { + class Commit; + +bool rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit); + +bool rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit); + +bool rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit); + +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index f18fdebba77..0ec2f6b1ef3 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -46,6 +46,7 @@ namespace frontend { RewriteObjC, ///< ObjC->C Rewriter. RewriteTest, ///< Rewriter playground RunAnalysis, ///< Run one or more source code analyses. + MigrateSource, ///< Run migrator. RunPreprocessorOnly ///< Just lex, no output. }; } @@ -118,7 +119,16 @@ public: ARCMT_Migrate } ARCMTAction; - std::string ARCMTMigrateDir; + enum { + ObjCMT_None = 0, + /// \brief Enable migration to modern ObjC literals. + ObjCMT_Literals = 0x1, + /// \brief Enable migration to modern ObjC subscripting. + ObjCMT_Subscripting = 0x2 + }; + unsigned ObjCMTAction; + + std::string MTMigrateDir; std::string ARCMTMigrateReportOut; /// The input files and their types. @@ -177,6 +187,7 @@ public: ShowVersion = 0; ARCMTAction = ARCMT_None; ARCMTMigrateEmitARCErrors = 0; + ObjCMTAction = ObjCMT_None; } /// getInputKindForExtension - Return the appropriate input kind for a file diff --git a/clang/include/clang/Rewrite/FixItRewriter.h b/clang/include/clang/Rewrite/FixItRewriter.h index 0ebd62c560f..44f0611b17e 100644 --- a/clang/include/clang/Rewrite/FixItRewriter.h +++ b/clang/include/clang/Rewrite/FixItRewriter.h @@ -18,6 +18,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Rewrite/Rewriter.h" +#include "clang/Edit/EditedSource.h" namespace clang { @@ -56,6 +57,8 @@ class FixItRewriter : public DiagnosticConsumer { /// \brief The diagnostics machinery. DiagnosticsEngine &Diags; + edit::EditedSource Editor; + /// \brief The rewriter used to perform the various code /// modifications. Rewriter Rewrite; diff --git a/clang/lib/ARCMigrate/ARCMT.cpp b/clang/lib/ARCMigrate/ARCMT.cpp index 61753074e82..07f22c4f369 100644 --- a/clang/lib/ARCMigrate/ARCMT.cpp +++ b/clang/lib/ARCMigrate/ARCMT.cpp @@ -398,13 +398,51 @@ bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > & if (err) return true; - CompilerInvocation CI; - remapper.applyMappings(CI); - remap = CI.getPreprocessorOpts().RemappedFiles; + PreprocessorOptions PPOpts; + remapper.applyMappings(PPOpts); + remap = PPOpts.RemappedFiles; return false; } +bool arcmt::getFileRemappingsFromFileList( + std::vector<std::pair<std::string,std::string> > &remap, + ArrayRef<StringRef> remapFiles, + DiagnosticConsumer *DiagClient) { + bool hasErrorOccurred = false; + llvm::StringMap<bool> Uniquer; + + llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + + for (ArrayRef<StringRef>::iterator + I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) { + StringRef file = *I; + + FileRemapper remapper; + bool err = remapper.initFromFile(file, *Diags, + /*ignoreIfFilesChanged=*/true); + hasErrorOccurred = hasErrorOccurred || err; + if (err) + continue; + + PreprocessorOptions PPOpts; + remapper.applyMappings(PPOpts); + for (PreprocessorOptions::remapped_file_iterator + RI = PPOpts.remapped_file_begin(), RE = PPOpts.remapped_file_end(); + RI != RE; ++RI) { + bool &inserted = Uniquer[RI->first]; + if (inserted) + continue; + inserted = true; + remap.push_back(*RI); + } + } + + return hasErrorOccurred; +} + //===----------------------------------------------------------------------===// // CollectTransformActions. //===----------------------------------------------------------------------===// @@ -504,7 +542,7 @@ bool MigrationProcess::applyTransform(TransformFn trans, CInvok.reset(createInvocationForMigration(OrigCI)); CInvok->getDiagnosticOpts().IgnoreWarnings = true; - Remapper.applyMappings(*CInvok); + Remapper.applyMappings(CInvok->getPreprocessorOpts()); CapturedDiagList capturedDiags; std::vector<SourceLocation> ARCMTMacroLocs; diff --git a/clang/lib/ARCMigrate/CMakeLists.txt b/clang/lib/ARCMigrate/CMakeLists.txt index 1a64b12721d..fcb7f72ee21 100644 --- a/clang/lib/ARCMigrate/CMakeLists.txt +++ b/clang/lib/ARCMigrate/CMakeLists.txt @@ -4,6 +4,7 @@ add_clang_library(clangARCMigrate ARCMT.cpp ARCMTActions.cpp FileRemapper.cpp + ObjCMT.cpp PlistReporter.cpp TransAPIUses.cpp TransARCAssign.cpp diff --git a/clang/lib/ARCMigrate/FileRemapper.cpp b/clang/lib/ARCMigrate/FileRemapper.cpp index 0e6e35c748f..1e97c9eed52 100644 --- a/clang/lib/ARCMigrate/FileRemapper.cpp +++ b/clang/lib/ARCMigrate/FileRemapper.cpp @@ -8,8 +8,9 @@ //===----------------------------------------------------------------------===// #include "clang/ARCMigrate/FileRemapper.h" -#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/PreprocessorOptions.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/Diagnostic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/FileSystem.h" @@ -50,9 +51,15 @@ std::string FileRemapper::getRemapInfoFile(StringRef outputDir) { bool FileRemapper::initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag, bool ignoreIfFilesChanged) { + std::string infoFile = getRemapInfoFile(outputDir); + return initFromFile(infoFile, Diag, ignoreIfFilesChanged); +} + +bool FileRemapper::initFromFile(StringRef filePath, DiagnosticsEngine &Diag, + bool ignoreIfFilesChanged) { assert(FromToMappings.empty() && "initFromDisk should be called before any remap calls"); - std::string infoFile = getRemapInfoFile(outputDir); + std::string infoFile = filePath; bool fileExists = false; llvm::sys::fs::exists(infoFile, fileExists); if (!fileExists) @@ -108,8 +115,15 @@ bool FileRemapper::flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag) { if (fs::create_directory(outputDir, existed) != llvm::errc::success) return report("Could not create directory: " + outputDir, Diag); - std::string errMsg; std::string infoFile = getRemapInfoFile(outputDir); + return flushToFile(infoFile, Diag); +} + +bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) { + using namespace llvm::sys; + + std::string errMsg; + std::string infoFile = outputPath; llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg, llvm::raw_fd_ostream::F_Binary); if (!errMsg.empty()) @@ -189,8 +203,7 @@ bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag, return false; } -void FileRemapper::applyMappings(CompilerInvocation &CI) const { - PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); +void FileRemapper::applyMappings(PreprocessorOptions &PPOpts) const { for (MappingsTy::const_iterator I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) { if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) { @@ -204,8 +217,7 @@ void FileRemapper::applyMappings(CompilerInvocation &CI) const { PPOpts.RetainRemappedFileBuffers = true; } -void FileRemapper::transferMappingsAndClear(CompilerInvocation &CI) { - PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); +void FileRemapper::transferMappingsAndClear(PreprocessorOptions &PPOpts) { for (MappingsTy::iterator I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) { if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) { diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp new file mode 100644 index 00000000000..497377a3943 --- /dev/null +++ b/clang/lib/ARCMigrate/ObjCMT.cpp @@ -0,0 +1,226 @@ +//===--- ObjCMT.cpp - ObjC Migrate Tool -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/ARCMigrate/ARCMTActions.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/MultiplexConsumer.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/NSAPI.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/Edit/Rewriters.h" +#include "clang/Edit/EditedSource.h" +#include "clang/Edit/Commit.h" +#include "clang/Edit/EditsReceiver.h" +#include "clang/Rewrite/Rewriter.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/FileManager.h" +#include "llvm/ADT/SmallString.h" + +using namespace clang; +using namespace arcmt; + +namespace { + +class ObjCMigrateASTConsumer : public ASTConsumer { + void migrateDecl(Decl *D); + +public: + std::string MigrateDir; + bool MigrateLiterals; + bool MigrateSubscripting; + llvm::OwningPtr<NSAPI> NSAPIObj; + llvm::OwningPtr<edit::EditedSource> Editor; + FileRemapper &Remapper; + FileManager &FileMgr; + const PreprocessingRecord *PPRec; + bool IsOutputFile; + + ObjCMigrateASTConsumer(StringRef migrateDir, + bool migrateLiterals, + bool migrateSubscripting, + FileRemapper &remapper, + FileManager &fileMgr, + const PreprocessingRecord *PPRec, + bool isOutputFile = false) + : MigrateDir(migrateDir), + MigrateLiterals(migrateLiterals), + MigrateSubscripting(migrateSubscripting), + Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), + IsOutputFile(isOutputFile) { } + +protected: + virtual void Initialize(ASTContext &Context) { + NSAPIObj.reset(new NSAPI(Context)); + Editor.reset(new edit::EditedSource(Context.getSourceManager(), + Context.getLangOptions(), + PPRec)); + } + + virtual bool HandleTopLevelDecl(DeclGroupRef DG) { + for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) + migrateDecl(*I); + return true; + } + virtual void HandleInterestingDecl(DeclGroupRef DG) { + // Ignore decls from the PCH. + } + virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) { + ObjCMigrateASTConsumer::HandleTopLevelDecl(DG); + } + + virtual void HandleTranslationUnit(ASTContext &Ctx); +}; + +} + +ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction, + StringRef migrateDir, + bool migrateLiterals, + bool migrateSubscripting) + : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir), + MigrateLiterals(migrateLiterals), MigrateSubscripting(migrateSubscripting), + CompInst(0) { + if (MigrateDir.empty()) + MigrateDir = "."; // user current directory if none is given. +} + +ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + ASTConsumer * + WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile); + ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir, + MigrateLiterals, + MigrateSubscripting, + Remapper, + CompInst->getFileManager(), + CompInst->getPreprocessor().getPreprocessingRecord()); + ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer }; + return new MultiplexConsumer(Consumers); +} + +bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) { + Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(), + /*ignoreIfFilesChanges=*/true); + CompInst = &CI; + CI.getDiagnostics().setIgnoreAllWarnings(true); + CI.getPreprocessorOpts().DetailedRecord = true; + CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true; + return true; +} + +namespace { +class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> { + ObjCMigrateASTConsumer &Consumer; + +public: + ObjCMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { } + + bool shouldVisitTemplateInstantiations() const { return false; } + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool VisitObjCMessageExpr(ObjCMessageExpr *E) { + if (Consumer.MigrateLiterals) { + edit::Commit commit(*Consumer.Editor); + edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit); + Consumer.Editor->commit(commit); + } + + if (Consumer.MigrateSubscripting) { + edit::Commit commit(*Consumer.Editor); + edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit); + Consumer.Editor->commit(commit); + } + + return true; + } + + bool TraverseObjCMessageExpr(ObjCMessageExpr *E) { + // Do depth first; we want to rewrite the subexpressions first so that if + // we have to move expressions we will move them already rewritten. + for (Stmt::child_range range = E->children(); range; ++range) + if (!TraverseStmt(*range)) + return false; + + return WalkUpFromObjCMessageExpr(E); + } +}; +} + +void ObjCMigrateASTConsumer::migrateDecl(Decl *D) { + if (!D) + return; + if (isa<ObjCMethodDecl>(D)) + return; // Wait for the ObjC container declaration. + + ObjCMigrator(*this).TraverseDecl(D); +} + +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); + } +}; + +} + +void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { + Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOptions()); + RewritesReceiver Rec(rewriter); + Editor->applyRewrites(Rec); + + for (Rewriter::buffer_iterator + I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { + FileID FID = I->first; + RewriteBuffer &buf = I->second; + const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); + assert(file); + llvm::SmallString<512> newText; + llvm::raw_svector_ostream vecOS(newText); + buf.write(vecOS); + vecOS.flush(); + llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( + StringRef(newText.data(), newText.size()), file->getName()); + llvm::SmallString<64> filePath(file->getName()); + FileMgr.FixupRelativePath(filePath); + Remapper.remap(filePath.str(), memBuf); + } + + if (IsOutputFile) { + Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics()); + } else { + Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics()); + } +} + +bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) { + CI.getPreprocessorOpts().DetailedRecord = true; + CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true; + return true; +} + +ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile, + /*MigrateLiterals=*/true, + /*MigrateSubscripting=*/true, + Remapper, + CI.getFileManager(), + CI.getPreprocessor().getPreprocessingRecord(), + /*isOutputFile=*/true); +} diff --git a/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp index 7bb7b5eeeae..15669ac973c 100644 --- a/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp +++ b/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp @@ -21,6 +21,8 @@ #include "Internals.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/AST/ParentMap.h" +#include "clang/Lex/Lexer.h" +#include "clang/Basic/SourceManager.h" using namespace clang; using namespace arcmt; @@ -128,27 +130,105 @@ public: Transaction Trans(Pass.TA); clearDiagnostics(rec->getExprLoc()); - if (E->getMethodFamily() == OMF_release && - isRemovable(E) && isInAtFinally(E)) { + ObjCMessageExpr *Msg = E; + Expr *RecContainer = Msg; + SourceRange RecRange = rec->getSourceRange(); + checkForGCDOrXPC(Msg, RecContainer, rec, RecRange); + + if (Msg->getMethodFamily() == OMF_release && + isRemovable(RecContainer) && isInAtFinally(RecContainer)) { // Change the -release to "receiver = nil" in a finally to avoid a leak // when an exception is thrown. - Pass.TA.replace(E->getSourceRange(), rec->getSourceRange()); + Pass.TA.replace(RecContainer->getSourceRange(), RecRange); std::string str = " = "; str += getNilString(Pass.Ctx); - Pass.TA.insertAfterToken(rec->getLocEnd(), str); + Pass.TA.insertAfterToken(RecRange.getEnd(), str); return true; } - if (!hasSideEffects(E, Pass.Ctx)) { - if (tryRemoving(E)) + if (!hasSideEffects(rec, Pass.Ctx)) { + if (tryRemoving(RecContainer)) return true; } - Pass.TA.replace(E->getSourceRange(), rec->getSourceRange()); + Pass.TA.replace(RecContainer->getSourceRange(), RecRange); return true; } private: + /// \brief Check if the retain/release is due to a GCD/XPC macro that are + /// defined as: + /// + /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; }) + /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; }) + /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; }) + /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; }) + /// + /// and return the top container which is the StmtExpr and the macro argument + /// expression. + void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer, + Expr *&Rec, SourceRange &RecRange) { + SourceLocation Loc = Msg->getExprLoc(); + if (!Loc.isMacroID()) + return; + SourceManager &SM = Pass.Ctx.getSourceManager(); + StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, + Pass.Ctx.getLangOptions()); + bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName) + .Case("dispatch_retain", true) + .Case("dispatch_release", true) + .Case("xpc_retain", true) + .Case("xpc_release", true) + .Default(false); + if (!isGCDOrXPC) + return; + + StmtExpr *StmtE = 0; + Stmt *S = Msg; + while (S) { + if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) { + StmtE = SE; + break; + } + S = StmtMap->getParent(S); + } + + if (!StmtE) + return; + + Stmt::child_range StmtExprChild = StmtE->children(); + if (!StmtExprChild) + return; + CompoundStmt *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild); + if (!CompS) + return; + + Stmt::child_range CompStmtChild = CompS->children(); + if (!CompStmtChild) + return; + DeclStmt *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild); + if (!DeclS) + return; + if (!DeclS->isSingleDecl()) + return; + VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()); + if (!VD) + return; + Expr *Init = VD->getInit(); + if (!Init) + return; + + RecContainer = StmtE; + Rec = Init->IgnoreParenImpCasts(); + if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Rec)) + Rec = EWC->getSubExpr()->IgnoreParenImpCasts(); + RecRange = Rec->getSourceRange(); + if (SM.isMacroArgExpansion(RecRange.getBegin())) + RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin())); + if (SM.isMacroArgExpansion(RecRange.getEnd())) + RecRange.setEnd(SM.getImmediateSpellingLoc(RecRange.getEnd())); + } + void clearDiagnostics(SourceLocation loc) const { Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message, diag::err_unavailable, diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp index f0e0c9c778f..8c33a963c92 100644 --- a/clang/lib/Basic/DiagnosticIDs.cpp +++ b/clang/lib/Basic/DiagnosticIDs.cpp @@ -657,19 +657,6 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const { } } - // If we have any Fix-Its, make sure that all of the Fix-Its point into - // source locations that aren't macro expansions. If any point into macro - // expansions, remove all of the Fix-Its. - for (unsigned I = 0, N = Diag.FixItHints.size(); I != N; ++I) { - const FixItHint &FixIt = Diag.FixItHints[I]; - if (FixIt.RemoveRange.isInvalid() || - FixIt.RemoveRange.getBegin().isMacroID() || - FixIt.RemoveRange.getEnd().isMacroID()) { - Diag.FixItHints.clear(); - break; - } - } - // Finally, report it. Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info); if (Diag.Client->IncludeInDiagnosticCounts()) { diff --git a/clang/lib/CMakeLists.txt b/clang/lib/CMakeLists.txt index 7b46c6040a9..54d296c3abb 100644 --- a/clang/lib/CMakeLists.txt +++ b/clang/lib/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(AST) add_subdirectory(Sema) add_subdirectory(CodeGen) add_subdirectory(Analysis) +add_subdirectory(Edit) add_subdirectory(Rewrite) add_subdirectory(ARCMigrate) add_subdirectory(Driver) diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp index a9dc17b320f..d7b4bc70530 100644 --- a/clang/lib/Driver/Action.cpp +++ b/clang/lib/Driver/Action.cpp @@ -27,6 +27,7 @@ const char *Action::getClassName(ActionClass AC) { case PreprocessJobClass: return "preprocessor"; case PrecompileJobClass: return "precompiler"; case AnalyzeJobClass: return "analyzer"; + case MigrateJobClass: return "migrator"; case CompileJobClass: return "compiler"; case AssembleJobClass: return "assembler"; case LinkJobClass: return "linker"; @@ -78,6 +79,12 @@ AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType) : JobAction(AnalyzeJobClass, Input, OutputType) { } +void MigrateJobAction::anchor() {} + +MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType) + : JobAction(MigrateJobClass, Input, OutputType) { +} + void CompileJobAction::anchor() {} CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index e71f5a60650..30b7eccc8a1 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -141,6 +141,7 @@ const { // -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler. } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) || (PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) || + (PhaseArg = DAL.getLastArg(options::OPT__migrate)) || (PhaseArg = DAL.getLastArg(options::OPT__analyze, options::OPT__analyze_auto)) || (PhaseArg = DAL.getLastArg(options::OPT_emit_ast)) || @@ -1140,6 +1141,8 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, return new CompileJobAction(Input, types::TY_RewrittenObjC); } else if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) { return new AnalyzeJobAction(Input, types::TY_Plist); + } else if (Args.hasArg(options::OPT__migrate)) { + return new MigrateJobAction(Input, types::TY_Remap); } else if (Args.hasArg(options::OPT_emit_ast)) { return new CompileJobAction(Input, types::TY_AST); } else if (IsUsingLTO(Args)) { diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index c0c9c504b6d..b4f5d0b4210 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -54,6 +54,7 @@ void ToolChain::configureObjCRuntime(ObjCRuntime &runtime) const { // Assume a minimal NeXT runtime. runtime.HasARC = false; runtime.HasWeak = false; + runtime.HasSubscripting = false; runtime.HasTerminate = false; return; @@ -61,6 +62,7 @@ void ToolChain::configureObjCRuntime(ObjCRuntime &runtime) const { // Assume a maximal GNU runtime. runtime.HasARC = true; runtime.HasWeak = true; + runtime.HasSubscripting = false; // to be added runtime.HasTerminate = false; // to be added return; } diff --git a/clang/lib/Driver/ToolChains.cpp b/clang/lib/Driver/ToolChains.cpp index 5ff82c76007..a45722315e4 100644 --- a/clang/lib/Driver/ToolChains.cpp +++ b/clang/lib/Driver/ToolChains.cpp @@ -227,6 +227,7 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA, case Action::PreprocessJobClass: T = new tools::darwin::Preprocess(*this); break; case Action::AnalyzeJobClass: + case Action::MigrateJobClass: T = new tools::Clang(*this); break; case Action::PrecompileJobClass: case Action::CompileJobClass: @@ -1409,6 +1410,7 @@ Tool &Generic_GCC::SelectTool(const Compilation &C, case Action::PrecompileJobClass: T = new tools::gcc::Precompile(*this); break; case Action::AnalyzeJobClass: + case Action::MigrateJobClass: T = new tools::Clang(*this); break; case Action::CompileJobClass: T = new tools::gcc::Compile(*this); break; diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 38f21c08829..076311a78ed 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -1247,6 +1247,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (isa<AnalyzeJobAction>(JA)) { assert(JA.getType() == types::TY_Plist && "Invalid output type."); CmdArgs.push_back("-analyze"); + } else if (isa<MigrateJobAction>(JA)) { + CmdArgs.push_back("-migrate"); } else if (isa<PreprocessJobAction>(JA)) { if (Output.getType() == types::TY_Dependencies) CmdArgs.push_back("-Eonly"); @@ -1716,10 +1718,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_working_directory); + bool ARCMTEnabled = false; if (!Args.hasArg(options::OPT_fno_objc_arc)) { if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check, options::OPT_ccc_arcmt_modify, options::OPT_ccc_arcmt_migrate)) { + ARCMTEnabled = true; switch (A->getOption().getID()) { default: llvm_unreachable("missed a case"); @@ -1731,7 +1735,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, break; case options::OPT_ccc_arcmt_migrate: CmdArgs.push_back("-arcmt-migrate"); - CmdArgs.push_back("-arcmt-migrate-directory"); + CmdArgs.push_back("-mt-migrate-directory"); CmdArgs.push_back(A->getValue(Args)); Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output); @@ -1741,6 +1745,25 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + if (const Arg *A = Args.getLastArg(options::OPT_ccc_objcmt_migrate)) { + if (ARCMTEnabled) { + D.Diag(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "-ccc-arcmt-migrate"; + } + CmdArgs.push_back("-mt-migrate-directory"); + CmdArgs.push_back(A->getValue(Args)); + + if (!Args.hasArg(options::OPT_objcmt_migrate_literals, + options::OPT_objcmt_migrate_subscripting)) { + // None specified, means enable them all. + CmdArgs.push_back("-objcmt-migrate-literals"); + CmdArgs.push_back("-objcmt-migrate-subscripting"); + } else { + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); + } + } + // Add preprocessing options like -I, -D, etc. if we are using the // preprocessor. // diff --git a/clang/lib/Driver/WindowsToolChain.cpp b/clang/lib/Driver/WindowsToolChain.cpp index 8a32db2fcad..70bd4f1fc36 100644 --- a/clang/lib/Driver/WindowsToolChain.cpp +++ b/clang/lib/Driver/WindowsToolChain.cpp @@ -59,6 +59,7 @@ Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA, case Action::PreprocessJobClass: case Action::PrecompileJobClass: case Action::AnalyzeJobClass: + case Action::MigrateJobClass: case Action::CompileJobClass: T = new tools::Clang(*this); break; case Action::AssembleJobClass: diff --git a/clang/lib/Edit/CMakeLists.txt b/clang/lib/Edit/CMakeLists.txt new file mode 100644 index 00000000000..c87478cf7d1 --- /dev/null +++ b/clang/lib/Edit/CMakeLists.txt @@ -0,0 +1,7 @@ +set(LLVM_USED_LIBS clangBasic clangAST clangLex) + +add_clang_library(clangEdit + Commit.cpp + EditedSource.cpp + RewriteObjCFoundationAPI.cpp + ) diff --git a/clang/lib/Edit/Commit.cpp b/clang/lib/Edit/Commit.cpp new file mode 100644 index 00000000000..e0250ccf056 --- /dev/null +++ b/clang/lib/Edit/Commit.cpp @@ -0,0 +1,345 @@ +//===----- Commit.cpp - A unit of edits -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Edit/Commit.h" +#include "clang/Edit/EditedSource.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Basic/SourceManager.h" + +using namespace clang; +using namespace edit; + +SourceLocation Commit::Edit::getFileLocation(SourceManager &SM) const { + SourceLocation Loc = SM.getLocForStartOfFile(Offset.getFID()); + Loc = Loc.getLocWithOffset(Offset.getOffset()); + assert(Loc.isFileID()); + return Loc; +} + +CharSourceRange Commit::Edit::getFileRange(SourceManager &SM) const { + SourceLocation Loc = getFileLocation(SM); + return CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(Length)); +} + +CharSourceRange Commit::Edit::getInsertFromRange(SourceManager &SM) const { + SourceLocation Loc = SM.getLocForStartOfFile(InsertFromRangeOffs.getFID()); + Loc = Loc.getLocWithOffset(InsertFromRangeOffs.getOffset()); + assert(Loc.isFileID()); + return CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(Length)); +} + +Commit::Commit(EditedSource &Editor) + : SourceMgr(Editor.getSourceManager()), LangOpts(Editor.getLangOptions()), + PPRec(Editor.getPreprocessingRecord()), + Editor(&Editor), IsCommitable(true) { } + +bool Commit::insert(SourceLocation loc, StringRef text, + bool afterToken, bool beforePreviousInsertions) { + if (text.empty()) + return true; + + FileOffset Offs; + if ((!afterToken && !canInsert(loc, Offs)) || + ( afterToken && !canInsertAfterToken(loc, Offs, loc))) { + IsCommitable = false; + return false; + } + + addInsert(loc, Offs, text, beforePreviousInsertions); + return true; +} + +bool Commit::insertFromRange(SourceLocation loc, + CharSourceRange range, + bool afterToken, bool beforePreviousInsertions) { + FileOffset RangeOffs; + unsigned RangeLen; + if (!canRemoveRange(range, RangeOffs, RangeLen)) { + IsCommitable = false; + return false; + } + + FileOffset Offs; + if ((!afterToken && !canInsert(loc, Offs)) || + ( afterToken && !canInsertAfterToken(loc, Offs, loc))) { + IsCommitable = false; + return false; + } + + if (PPRec && + PPRec->areInDifferentConditionalDirectiveRegion(loc, range.getBegin())) { + IsCommitable = false; + return false; + } + + addInsertFromRange(loc, Offs, RangeOffs, RangeLen, beforePreviousInsertions); + return true; +} + +bool Commit::remove(CharSourceRange range) { + FileOffset Offs; + unsigned Len; + if (!canRemoveRange(range, Offs, Len)) { + IsCommitable = false; + return false; + } + + addRemove(range.getBegin(), Offs, Len); + return true; +} + +bool Commit::insertWrap(StringRef before, CharSourceRange range, + StringRef after) { + bool commitableBefore = insert(range.getBegin(), before, /*afterToken=*/false, + /*beforePreviousInsertions=*/true); + bool commitableAfter; + if (range.isTokenRange()) + commitableAfter = insertAfterToken(range.getEnd(), after); + else + commitableAfter = insert(range.getEnd(), after); + + return commitableBefore && commitableAfter; +} + +bool Commit::replace(CharSourceRange range, StringRef text) { + if (text.empty()) + return remove(range); + + FileOffset Offs; + unsigned Len; + if (!canInsert(range.getBegin(), Offs) || !canRemoveRange(range, Offs, Len)) { + IsCommitable = false; + return false; + } + + addRemove(range.getBegin(), Offs, Len); + addInsert(range.getBegin(), Offs, text, false); + return true; +} + +bool Commit::replaceWithInner(CharSourceRange range, + CharSourceRange replacementRange) { + FileOffset OuterBegin; + unsigned OuterLen; + if (!canRemoveRange(range, OuterBegin, OuterLen)) { + IsCommitable = false; + return false; + } + + FileOffset InnerBegin; + unsigned InnerLen; + if (!canRemoveRange(replacementRange, InnerBegin, InnerLen)) { + IsCommitable = false; + return false; + } + + FileOffset OuterEnd = OuterBegin.getWithOffset(OuterLen); + FileOffset InnerEnd = InnerBegin.getWithOffset(InnerLen); + if (OuterBegin.getFID() != InnerBegin.getFID() || + InnerBegin < OuterBegin || + InnerBegin > OuterEnd || + InnerEnd > OuterEnd) { + IsCommitable = false; + return false; + } + + addRemove(range.getBegin(), + OuterBegin, InnerBegin.getOffset() - OuterBegin.getOffset()); + addRemove(replacementRange.getEnd(), + InnerEnd, OuterEnd.getOffset() - InnerEnd.getOffset()); + return true; +} + +bool Commit::replaceText(SourceLocation loc, StringRef text, + StringRef replacementText) { + if (text.empty() || replacementText.empty()) + return true; + + FileOffset Offs; + unsigned Len; + if (!canReplaceText(loc, replacementText, Offs, Len)) { + IsCommitable = false; + return false; + } + + addRemove(loc, Offs, Len); + addInsert(loc, Offs, text, false); + return true; +} + +void Commit::addInsert(SourceLocation OrigLoc, FileOffset Offs, StringRef text, + bool beforePreviousInsertions) { + if (text.empty()) + return; + + Edit data; + data.Kind = Act_Insert; + data.OrigLoc = OrigLoc; + data.Offset = Offs; + data.Text = text; + data.BeforePrev = beforePreviousInsertions; + CachedEdits.push_back(data); +} + +void Commit::addInsertFromRange(SourceLocation OrigLoc, FileOffset Offs, + FileOffset RangeOffs, unsigned RangeLen, + bool beforePreviousInsertions) { + if (RangeLen == 0) + return; + + Edit data; + data.Kind = Act_InsertFromRange; + data.OrigLoc = OrigLoc; + data.Offset = Offs; + data.InsertFromRangeOffs = RangeOffs; + data.Length = RangeLen; + data.BeforePrev = beforePreviousInsertions; + CachedEdits.push_back(data); +} + +void Commit::addRemove(SourceLocation OrigLoc, + FileOffset Offs, unsigned Len) { + if (Len == 0) + return; + + Edit data; + data.Kind = Act_Remove; + data.OrigLoc = OrigLoc; + data.Offset = Offs; + data.Length = Len; + CachedEdits.push_back(data); +} + +bool Commit::canInsert(SourceLocation loc, FileOffset &offs) { + if (loc.isInvalid()) + return false; + + if (loc.isMacroID()) + isAtStartOfMacroExpansion(loc, &loc); + + const SourceManager &SM = SourceMgr; + while (SM.isMacroArgExpansion(loc)) + loc = SM.getImmediateSpellingLoc(loc); + + if (loc.isMacroID()) + if (!isAtStartOfMacroExpansion(loc, &loc)) + return false; + + if (SM.isInSystemHeader(loc)) + return false; + + std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); + if (locInfo.first.isInvalid()) + return false; + offs = FileOffset(locInfo.first, locInfo.second); + return canInsertInOffset(loc, offs); +} + +bool Commit::canInsertAfterToken(SourceLocation loc, FileOffset &offs, + SourceLocation &AfterLoc) { + if (loc.isInvalid()) + + return false; + + SourceLocation spellLoc = SourceMgr.getSpellingLoc(loc); + unsigned tokLen = Lexer::MeasureTokenLength(spellLoc, SourceMgr, LangOpts); + AfterLoc = loc.getLocWithOffset(tokLen); + + if (loc.isMacroID()) + isAtEndOfMacroExpansion(loc, &loc); + + const SourceManager &SM = SourceMgr; + while (SM.isMacroArgExpansion(loc)) + loc = SM.getImmediateSpellingLoc(loc); + + if (loc.isMacroID()) + if (!isAtEndOfMacroExpansion(loc, &loc)) + return false; + + if (SM.isInSystemHeader(loc)) + return false; + + loc = Lexer::getLocForEndOfToken(loc, 0, SourceMgr, LangOpts); + if (loc.isInvalid()) + return false; + + std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); + if (locInfo.first.isInvalid()) + return false; + offs = FileOffset(locInfo.first, locInfo.second); + return canInsertInOffset(loc, offs); +} + +bool Commit::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) { + for (unsigned i = 0, e = CachedEdits.size(); i != e; ++i) { + Edit &act = CachedEdits[i]; + if (act.Kind == Act_Remove) { + if (act.Offset.getFID() == Offs.getFID() && + Offs > act.Offset && Offs < act.Offset.getWithOffset(act.Length)) + return false; // position has been removed. + } + } + + if (!Editor) + return true; + return Editor->canInsertInOffset(OrigLoc, Offs); +} + +bool Commit::canRemoveRange(CharSourceRange range, + FileOffset &Offs, unsigned &Len) { + const SourceManager &SM = SourceMgr; + range = Lexer::makeFileCharRange(range, SM, LangOpts); + if (range.isInvalid()) + return false; + + if (range.getBegin().isMacroID() || range.getEnd().isMacroID()) + return false; + if (SM.isInSystemHeader(range.getBegin()) || + SM.isInSystemHeader(range.getEnd())) + return false; + + if (PPRec && PPRec->rangeIntersectsConditionalDirective(range.getAsRange())) + return false; + + std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(range.getBegin()); + std::pair<FileID, unsigned> endInfo = SM.getDecomposedLoc(range.getEnd()); + if (beginInfo.first != endInfo.first || + beginInfo.second > endInfo.second) + return false; + + Offs = FileOffset(beginInfo.first, beginInfo.second); + Len = endInfo.second - beginInfo.second; + return true; +} + +bool Commit::canReplaceText(SourceLocation loc, StringRef text, + FileOffset &Offs, unsigned &Len) { + assert(!text.empty()); + + if (!canInsert(loc, Offs)) + return false; + + // Try to load the file buffer. + bool invalidTemp = false; + StringRef file = SourceMgr.getBufferData(Offs.getFID(), &invalidTemp); + if (invalidTemp) + return false; + + return file.substr(Offs.getOffset()).startswith(text); +} + +bool Commit::isAtStartOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroBegin) const { + return Lexer::isAtStartOfMacroExpansion(loc, SourceMgr, LangOpts, MacroBegin); +} +bool Commit::isAtEndOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroEnd) const { + return Lexer::isAtEndOfMacroExpansion(loc, SourceMgr, LangOpts, MacroEnd); +} diff --git a/clang/lib/Edit/EditedSource.cpp b/clang/lib/Edit/EditedSource.cpp new file mode 100644 index 00000000000..5b7fa4ad1b6 --- /dev/null +++ b/clang/lib/Edit/EditedSource.cpp @@ -0,0 +1,329 @@ +//===----- EditedSource.cpp - Collection of source edits ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Edit/EditedSource.h" +#include "clang/Edit/Commit.h" +#include "clang/Edit/EditsReceiver.h" +#include "clang/Lex/Lexer.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" + +using namespace clang; +using namespace edit; + +void EditsReceiver::remove(CharSourceRange range) { + replace(range, StringRef()); +} + +StringRef EditedSource::copyString(const Twine &twine) { + llvm::SmallString<128> Data; + return copyString(twine.toStringRef(Data)); +} + +bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) { + FileEditsTy::iterator FA = getActionForOffset(Offs); + if (FA != FileEdits.end()) { + if (FA->first != Offs) + return false; // position has been removed. + } + + if (SourceMgr.isMacroArgExpansion(OrigLoc)) { + SourceLocation + DefArgLoc = SourceMgr.getImmediateExpansionRange(OrigLoc).first; + SourceLocation + ExpLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first; + llvm::DenseMap<unsigned, SourceLocation>::iterator + I = ExpansionToArgMap.find(ExpLoc.getRawEncoding()); + if (I != ExpansionToArgMap.end() && I->second != DefArgLoc) + return false; // Trying to write in a macro argument input that has + // already been written for another argument of the same macro. + } + + return true; +} + +bool EditedSource::commitInsert(SourceLocation OrigLoc, + FileOffset Offs, StringRef text, + bool beforePreviousInsertions) { + if (!canInsertInOffset(OrigLoc, Offs)) + return false; + if (text.empty()) + return true; + + if (SourceMgr.isMacroArgExpansion(OrigLoc)) { + SourceLocation + DefArgLoc = SourceMgr.getImmediateExpansionRange(OrigLoc).first; + SourceLocation + ExpLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first; + ExpansionToArgMap[ExpLoc.getRawEncoding()] = DefArgLoc; + } + + FileEdit &FA = FileEdits[Offs]; + if (FA.Text.empty()) { + FA.Text = copyString(text); + return true; + } + + Twine concat; + if (beforePreviousInsertions) + concat = Twine(text) + FA.Text; + else + concat = Twine(FA.Text) + text; + + FA.Text = copyString(concat); + return true; +} + +bool EditedSource::commitInsertFromRange(SourceLocation OrigLoc, + FileOffset Offs, + FileOffset InsertFromRangeOffs, unsigned Len, + bool beforePreviousInsertions) { + if (Len == 0) + return true; + + llvm::SmallString<128> StrVec; + FileOffset BeginOffs = InsertFromRangeOffs; + FileOffset EndOffs = BeginOffs.getWithOffset(Len); + FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs); + if (I != FileEdits.begin()) + --I; + + for (; I != FileEdits.end(); ++I) { + FileEdit &FA = I->second; + FileOffset B = I->first; + FileOffset E = B.getWithOffset(FA.RemoveLen); + + if (BeginOffs < E) { + if (BeginOffs >= B) { + BeginOffs = E; + ++I; + } + break; + } + } + + for (; I != FileEdits.end() && EndOffs > I->first; ++I) { + FileEdit &FA = I->second; + FileOffset B = I->first; + FileOffset E = B.getWithOffset(FA.RemoveLen); + + if (BeginOffs < B) { + bool Invalid = false; + StringRef text = getSourceText(BeginOffs, B, Invalid); + if (Invalid) + return false; + StrVec += text; + } + StrVec += FA.Text; + BeginOffs = E; + } + + if (BeginOffs < EndOffs) { + bool Invalid = false; + StringRef text = getSourceText(BeginOffs, EndOffs, Invalid); + if (Invalid) + return false; + StrVec += text; + } + + return commitInsert(OrigLoc, Offs, StrVec.str(), beforePreviousInsertions); +} + +void EditedSource::commitRemove(SourceLocation OrigLoc, + FileOffset BeginOffs, unsigned Len) { + if (Len == 0) + return; + + FileOffset EndOffs = BeginOffs.getWithOffset(Len); + FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs); + if (I != FileEdits.begin()) + --I; + + for (; I != FileEdits.end(); ++I) { + FileEdit &FA = I->second; + FileOffset B = I->first; + FileOffset E = B.getWithOffset(FA.RemoveLen); + + if (BeginOffs < E) + break; + } + + FileOffset TopBegin, TopEnd; + FileEdit *TopFA = 0; + + if (I == FileEdits.end()) { + FileEditsTy::iterator + NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit())); + NewI->second.RemoveLen = Len; + return; + } + + FileEdit &FA = I->second; + FileOffset B = I->first; + FileOffset E = B.getWithOffset(FA.RemoveLen); + if (BeginOffs < B) { + FileEditsTy::iterator + NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit())); + TopBegin = BeginOffs; + TopEnd = EndOffs; + TopFA = &NewI->second; + TopFA->RemoveLen = Len; + } else { + TopBegin = B; + TopEnd = E; + TopFA = &I->second; + if (TopEnd >= EndOffs) + return; + unsigned diff = EndOffs.getOffset() - TopEnd.getOffset(); + TopEnd = EndOffs; + TopFA->RemoveLen += diff; + ++I; + } + + while (I != FileEdits.end()) { + FileEdit &FA = I->second; + FileOffset B = I->first; + FileOffset E = B.getWithOffset(FA.RemoveLen); + + if (B >= TopEnd) + break; + + if (E <= TopEnd) { + FileEdits.erase(I++); + continue; + } + + if (B < TopEnd) { + unsigned diff = E.getOffset() - TopEnd.getOffset(); + TopEnd = E; + TopFA->RemoveLen += diff; + FileEdits.erase(I); + } + + break; + } +} + +bool EditedSource::commit(const Commit &commit) { + if (!commit.isCommitable()) + return false; + + for (edit::Commit::edit_iterator + I = commit.edit_begin(), E = commit.edit_end(); I != E; ++I) { + const edit::Commit::Edit &edit = *I; + switch (edit.Kind) { + case edit::Commit::Act_Insert: + commitInsert(edit.OrigLoc, edit.Offset, edit.Text, edit.BeforePrev); + break; + case edit::Commit::Act_InsertFromRange: + commitInsertFromRange(edit.OrigLoc, edit.Offset, + edit.InsertFromRangeOffs, edit.Length, + edit.BeforePrev); + break; + case edit::Commit::Act_Remove: + commitRemove(edit.OrigLoc, edit.Offset, edit.Length); + break; + } + } + + return true; +} + +static void applyRewrite(EditsReceiver &receiver, + StringRef text, FileOffset offs, unsigned len, + const SourceManager &SM) { + assert(!offs.getFID().isInvalid()); + SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID()); + Loc = Loc.getLocWithOffset(offs.getOffset()); + assert(Loc.isFileID()); + CharSourceRange range = CharSourceRange::getCharRange(Loc, + Loc.getLocWithOffset(len)); + + if (text.empty()) { + assert(len); + receiver.remove(range); + return; + } + + if (len) + receiver.replace(range, text); + else + receiver.insert(Loc, text); +} + +void EditedSource::applyRewrites(EditsReceiver &receiver) { + llvm::SmallString<128> StrVec; + FileOffset CurOffs, CurEnd; + unsigned CurLen; + + if (FileEdits.empty()) + return; + + FileEditsTy::iterator I = FileEdits.begin(); + CurOffs = I->first; + StrVec = I->second.Text; + CurLen = I->second.RemoveLen; + CurEnd = CurOffs.getWithOffset(CurLen); + ++I; + + for (FileEditsTy::iterator E = FileEdits.end(); I != E; ++I) { + FileOffset offs = I->first; + FileEdit act = I->second; + assert(offs >= CurEnd); + + if (offs == CurEnd) { + StrVec += act.Text; + CurLen += act.RemoveLen; + CurEnd.getWithOffset(act.RemoveLen); + continue; + } + + applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr); + CurOffs = offs; + StrVec = act.Text; + CurLen = act.RemoveLen; + CurEnd = CurOffs.getWithOffset(CurLen); + } + + applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr); +} + +void EditedSource::clearRewrites() { + FileEdits.clear(); + StrAlloc.Reset(); +} + +StringRef EditedSource::getSourceText(FileOffset BeginOffs, FileOffset EndOffs, + bool &Invalid) { + assert(BeginOffs.getFID() == EndOffs.getFID()); + assert(BeginOffs <= EndOffs); + SourceLocation BLoc = SourceMgr.getLocForStartOfFile(BeginOffs.getFID()); + BLoc = BLoc.getLocWithOffset(BeginOffs.getOffset()); + assert(BLoc.isFileID()); + SourceLocation + ELoc = BLoc.getLocWithOffset(EndOffs.getOffset() - BeginOffs.getOffset()); + return Lexer::getSourceText(CharSourceRange::getCharRange(BLoc, ELoc), + SourceMgr, LangOpts, &Invalid); +} + +EditedSource::FileEditsTy::iterator +EditedSource::getActionForOffset(FileOffset Offs) { + FileEditsTy::iterator I = FileEdits.upper_bound(Offs); + if (I == FileEdits.begin()) + return FileEdits.end(); + --I; + FileEdit &FA = I->second; + FileOffset B = I->first; + FileOffset E = B.getWithOffset(FA.RemoveLen); + if (Offs >= B && Offs < E) + return I; + + return FileEdits.end(); +} diff --git a/clang/lib/Edit/Makefile b/clang/lib/Edit/Makefile new file mode 100644 index 00000000000..92a67ebc829 --- /dev/null +++ b/clang/lib/Edit/Makefile @@ -0,0 +1,14 @@ +##===- clang/lib/Edit/Makefile -----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../.. +LIBRARYNAME := clangEdit + +include $(CLANG_LEVEL)/Makefile + diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp new file mode 100644 index 00000000000..a0927680345 --- /dev/null +++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -0,0 +1,589 @@ +//===--- RewriteObjCFoundationAPI.cpp - Foundation API Rewriter -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Rewrites legacy method calls to modern syntax. +// +//===----------------------------------------------------------------------===// + +#include "clang/Edit/Rewriters.h" +#include "clang/Edit/Commit.h" +#include "clang/Lex/Lexer.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/NSAPI.h" + +using namespace clang; +using namespace edit; + +static bool checkForLiteralCreation(const ObjCMessageExpr *Msg, + IdentifierInfo *&ClassId) { + if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl()) + return false; + + const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface(); + if (!Receiver) + return false; + ClassId = Receiver->getIdentifier(); + + if (Msg->getReceiverKind() == ObjCMessageExpr::Class) + return true; + + return false; +} + +//===----------------------------------------------------------------------===// +// rewriteObjCRedundantCallWithLiteral. +//===----------------------------------------------------------------------===// + +bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit) { + IdentifierInfo *II = 0; + if (!checkForLiteralCreation(Msg, II)) + return false; + if (Msg->getNumArgs() != 1) + return false; + + const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts(); + Selector Sel = Msg->getSelector(); + + if ((isa<ObjCStringLiteral>(Arg) && + NS.getNSClassId(NSAPI::ClassId_NSString) == II && + NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel) || + + (isa<ObjCArrayLiteral>(Arg) && + NS.getNSClassId(NSAPI::ClassId_NSArray) == II && + NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel) || + + (isa<ObjCDictionaryLiteral>(Arg) && + NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II && + NS.getNSDictionarySelector( + NSAPI::NSDict_dictionaryWithDictionary) == Sel)) { + + commit.replaceWithInner(Msg->getSourceRange(), + Msg->getArg(0)->getSourceRange()); + return true; + } + + return false; +} + +//===----------------------------------------------------------------------===// +// rewriteToObjCSubscriptSyntax. +//===----------------------------------------------------------------------===// + +static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) { + Receiver = Receiver->IgnoreImpCasts(); + if (isa<BinaryOperator>(Receiver) || isa<UnaryOperator>(Receiver)) { + SourceRange RecRange = Receiver->getSourceRange(); + commit.insertWrap("(", RecRange, ")"); + } +} + +static bool rewriteToSubscriptGet(const ObjCMessageExpr *Msg, Commit &commit) { + if (Msg->getNumArgs() != 1) + return false; + const Expr *Rec = Msg->getInstanceReceiver(); + if (!Rec) + return false; + + SourceRange MsgRange = Msg->getSourceRange(); + SourceRange RecRange = Rec->getSourceRange(); + SourceRange ArgRange = Msg->getArg(0)->getSourceRange(); + + commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(), + ArgRange.getBegin()), + CharSourceRange::getTokenRange(RecRange)); + commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()), + ArgRange); + commit.insertWrap("[", ArgRange, "]"); + maybePutParensOnReceiver(Rec, commit); + return true; +} + +static bool rewriteToArraySubscriptSet(const ObjCMessageExpr *Msg, + Commit &commit) { + if (Msg->getNumArgs() != 2) + return false; + const Expr *Rec = Msg->getInstanceReceiver(); + if (!Rec) + return false; + + SourceRange MsgRange = Msg->getSourceRange(); + SourceRange RecRange = Rec->getSourceRange(); + SourceRange Arg0Range = Msg->getArg(0)->getSourceRange(); + SourceRange Arg1Range = Msg->getArg(1)->getSourceRange(); + + commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(), + Arg0Range.getBegin()), + CharSourceRange::getTokenRange(RecRange)); + commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(), + Arg1Range.getBegin()), + CharSourceRange::getTokenRange(Arg0Range)); + commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()), + Arg1Range); + commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(), + Arg1Range.getBegin()), + "] = "); + maybePutParensOnReceiver(Rec, commit); + return true; +} + +static bool rewriteToDictionarySubscriptSet(const ObjCMessageExpr *Msg, + Commit &commit) { + if (Msg->getNumArgs() != 2) + return false; + const Expr *Rec = Msg->getInstanceReceiver(); + if (!Rec) + return false; + + SourceRange MsgRange = Msg->getSourceRange(); + SourceRange RecRange = Rec->getSourceRange(); + SourceRange Arg0Range = Msg->getArg(0)->getSourceRange(); + SourceRange Arg1Range = Msg->getArg(1)->getSourceRange(); + + SourceLocation LocBeforeVal = Arg0Range.getBegin(); + commit.insertBefore(LocBeforeVal, "] = "); + commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false, + /*beforePreviousInsertions=*/true); + commit.insertBefore(LocBeforeVal, "["); + commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(), + Arg0Range.getBegin()), + CharSourceRange::getTokenRange(RecRange)); + commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()), + Arg0Range); + maybePutParensOnReceiver(Rec, commit); + return true; +} + +bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit) { + if (!Msg || Msg->isImplicit() || + Msg->getReceiverKind() != ObjCMessageExpr::Instance) + return false; + const ObjCMethodDecl *Method = Msg->getMethodDecl(); + if (!Method) + return false; + + const ObjCInterfaceDecl * + IFace = NS.getASTContext().getObjContainingInterface( + const_cast<ObjCMethodDecl *>(Method)); + if (!IFace) + return false; + IdentifierInfo *II = IFace->getIdentifier(); + Selector Sel = Msg->getSelector(); + + if ((II == NS.getNSClassId(NSAPI::ClassId_NSArray) && + Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex)) || + (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary) && + Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey))) + return rewriteToSubscriptGet(Msg, commit); + + if (Msg->getNumArgs() != 2) + return false; + + if (II == NS.getNSClassId(NSAPI::ClassId_NSMutableArray) && + Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex)) + return rewriteToArraySubscriptSet(Msg, commit); + + if (II == NS.getNSClassId(NSAPI::ClassId_NSMutableDictionary) && + Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey)) + return rewriteToDictionarySubscriptSet(Msg, commit); + + return false; +} + +//===----------------------------------------------------------------------===// +// rewriteToObjCLiteralSyntax. +//===----------------------------------------------------------------------===// + +static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit); +static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit); +static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit); + +bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit) { + IdentifierInfo *II = 0; + if (!checkForLiteralCreation(Msg, II)) + return false; + + if (II == NS.getNSClassId(NSAPI::ClassId_NSArray)) + return rewriteToArrayLiteral(Msg, NS, commit); + if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary)) + return rewriteToDictionaryLiteral(Msg, NS, commit); + if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber)) + return rewriteToNumberLiteral(Msg, NS, commit); + + return false; +} + +//===----------------------------------------------------------------------===// +// rewriteToArrayLiteral. +//===----------------------------------------------------------------------===// + +static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit) { + Selector Sel = Msg->getSelector(); + SourceRange MsgRange = Msg->getSourceRange(); + + if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) { + if (Msg->getNumArgs() != 0) + return false; + commit.replace(MsgRange, "@[]"); + return true; + } + + if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) { + if (Msg->getNumArgs() != 1) + return false; + SourceRange ArgRange = Msg->getArg(0)->getSourceRange(); + commit.replaceWithInner(MsgRange, ArgRange); + commit.insertWrap("@[", ArgRange, "]"); + return true; + } + + if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects)) { + if (Msg->getNumArgs() == 0) + return false; + const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1); + if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr)) + return false; + + if (Msg->getNumArgs() == 1) { + commit.replace(MsgRange, "@[]"); + return true; + } + SourceRange ArgRange(Msg->getArg(0)->getLocStart(), + Msg->getArg(Msg->getNumArgs()-2)->getLocEnd()); + commit.replaceWithInner(MsgRange, ArgRange); + commit.insertWrap("@[", ArgRange, "]"); + return true; + } + + return false; +} + +//===----------------------------------------------------------------------===// +// rewriteToDictionaryLiteral. +//===----------------------------------------------------------------------===// + +static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit) { + Selector Sel = Msg->getSelector(); + SourceRange MsgRange = Msg->getSourceRange(); + + if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) { + if (Msg->getNumArgs() != 0) + return false; + commit.replace(MsgRange, "@{}"); + return true; + } + + if (Sel == NS.getNSDictionarySelector( + NSAPI::NSDict_dictionaryWithObjectForKey)) { + if (Msg->getNumArgs() != 2) + return false; + SourceRange ValRange = Msg->getArg(0)->getSourceRange(); + SourceRange KeyRange = Msg->getArg(1)->getSourceRange(); + // Insert key before the value. + commit.insertBefore(ValRange.getBegin(), ": "); + commit.insertFromRange(ValRange.getBegin(), + CharSourceRange::getTokenRange(KeyRange), + /*afterToken=*/false, /*beforePreviousInsertions=*/true); + commit.insertBefore(ValRange.getBegin(), "@{"); + commit.insertAfterToken(ValRange.getEnd(), "}"); + commit.replaceWithInner(MsgRange, ValRange); + return true; + } + + if (Sel == NS.getNSDictionarySelector( + NSAPI::NSDict_dictionaryWithObjectsAndKeys)) { + if (Msg->getNumArgs() % 2 != 1) + return false; + unsigned SentinelIdx = Msg->getNumArgs() - 1; + const Expr *SentinelExpr = Msg->getArg(SentinelIdx); + if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr)) + return false; + + if (Msg->getNumArgs() == 1) { + commit.replace(MsgRange, "@{}"); + return true; + } + + for (unsigned i = 0; i < SentinelIdx; i += 2) { + SourceRange ValRange = Msg->getArg(i)->getSourceRange(); + SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange(); + // Insert value after key. + commit.insertAfterToken(KeyRange.getEnd(), ": "); + commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true); + commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(), + KeyRange.getBegin())); + } + // Range of arguments up until and including the last key. + // The sentinel and first value are cut off, the value will move after the + // key. + SourceRange ArgRange(Msg->getArg(1)->getLocStart(), + Msg->getArg(SentinelIdx-1)->getLocEnd()); + commit.insertWrap("@{", ArgRange, "}"); + commit.replaceWithInner(MsgRange, ArgRange); + return true; + } + + return false; +} + +//===----------------------------------------------------------------------===// +// rewriteToNumberLiteral. +//===----------------------------------------------------------------------===// + +static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg, + const CharacterLiteral *Arg, + const NSAPI &NS, Commit &commit) { + if (Arg->getKind() != CharacterLiteral::Ascii) + return false; + if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar, + Msg->getSelector())) { + SourceRange ArgRange = Arg->getSourceRange(); + commit.replaceWithInner(Msg->getSourceRange(), ArgRange); + commit.insert(ArgRange.getBegin(), "@"); + return true; + } + + return false; +} + +static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg, + const Expr *Arg, + const NSAPI &NS, Commit &commit) { + if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool, + Msg->getSelector())) { + SourceRange ArgRange = Arg->getSourceRange(); + commit.replaceWithInner(Msg->getSourceRange(), ArgRange); + commit.insert(ArgRange.getBegin(), "@"); + return true; + } + + return false; +} + +namespace { + +struct LiteralInfo { + bool Hex, Octal; + StringRef U, F, L, LL; + CharSourceRange WithoutSuffRange; +}; + +} + +static bool getLiteralInfo(SourceRange literalRange, + bool isFloat, bool isIntZero, + ASTContext &Ctx, LiteralInfo &Info) { + if (literalRange.getBegin().isMacroID() || + literalRange.getEnd().isMacroID()) + return false; + StringRef text = Lexer::getSourceText( + CharSourceRange::getTokenRange(literalRange), + Ctx.getSourceManager(), Ctx.getLangOptions()); + if (text.empty()) + return false; + + llvm::Optional<bool> UpperU, UpperL; + bool UpperF = false; + + struct Suff { + static bool has(StringRef suff, StringRef &text) { + if (text.endswith(suff)) { + text = text.substr(0, text.size()-suff.size()); + return true; + } + return false; + } + }; + + while (1) { + if (Suff::has("u", text)) { + UpperU = false; + } else if (Suff::has("U", text)) { + UpperU = true; + } else if (Suff::has("ll", text)) { + UpperL = false; + } else if (Suff::has("LL", text)) { + UpperL = true; + } else if (Suff::has("l", text)) { + UpperL = false; + } else if (Suff::has("L", text)) { + UpperL = true; + } else if (isFloat && Suff::has("f", text)) { + UpperF = false; + } else if (isFloat && Suff::has("F", text)) { + UpperF = true; + } else + break; + } + + if (!UpperU.hasValue() && !UpperL.hasValue()) + UpperU = UpperL = true; + else if (UpperU.hasValue() && !UpperL.hasValue()) + UpperL = UpperU; + else if (UpperL.hasValue() && !UpperU.hasValue()) + UpperU = UpperL; + + Info.U = *UpperU ? "U" : "u"; + Info.L = *UpperL ? "L" : "l"; + Info.LL = *UpperL ? "LL" : "ll"; + Info.F = UpperF ? "F" : "f"; + + Info.Hex = Info.Octal = false; + if (text.startswith("0x")) + Info.Hex = true; + else if (!isFloat && !isIntZero && text.startswith("0")) + Info.Octal = true; + + SourceLocation B = literalRange.getBegin(); + Info.WithoutSuffRange = + CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size())); + return true; +} + +static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit) { + if (Msg->getNumArgs() != 1) + return false; + + const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts(); + if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg)) + return rewriteToCharLiteral(Msg, CharE, NS, commit); + if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg)) + return rewriteToBoolLiteral(Msg, BE, NS, commit); + if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg)) + return rewriteToBoolLiteral(Msg, BE, NS, commit); + + const Expr *literalE = Arg; + if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) { + if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus) + literalE = UOE->getSubExpr(); + } + + // Only integer and floating literals; non-literals or imaginary literal + // cannot be rewritten. + if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE)) + return false; + + ASTContext &Ctx = NS.getASTContext(); + Selector Sel = Msg->getSelector(); + llvm::Optional<NSAPI::NSNumberLiteralMethodKind> + MKOpt = NS.getNSNumberLiteralMethodKind(Sel); + if (!MKOpt) + return false; + NSAPI::NSNumberLiteralMethodKind MK = *MKOpt; + + bool CallIsInteger = false, CallIsUnsigned = false; + bool CallIsLong = false, CallIsLongLong = false; + bool CallIsFloating = false, CallIsDouble = false; + + switch (MK) { + // We cannot have these calls with int/float literals. + case NSAPI::NSNumberWithChar: + case NSAPI::NSNumberWithUnsignedChar: + case NSAPI::NSNumberWithShort: + case NSAPI::NSNumberWithUnsignedShort: + case NSAPI::NSNumberWithBool: + return false; + + case NSAPI::NSNumberWithUnsignedInt: + case NSAPI::NSNumberWithUnsignedInteger: + CallIsUnsigned = true; + case NSAPI::NSNumberWithInt: + case NSAPI::NSNumberWithInteger: + CallIsInteger = true; + break; + + case NSAPI::NSNumberWithUnsignedLong: + CallIsUnsigned = true; + case NSAPI::NSNumberWithLong: + CallIsInteger = true; CallIsLong = true; + break; + + case NSAPI::NSNumberWithUnsignedLongLong: + CallIsUnsigned = true; + case NSAPI::NSNumberWithLongLong: + CallIsInteger = true; CallIsLongLong = true; + break; + + case NSAPI::NSNumberWithDouble: + CallIsDouble = true; + case NSAPI::NSNumberWithFloat: + CallIsFloating = true; + break; + } + + SourceRange ArgRange = Arg->getSourceRange(); + QualType ArgTy = Arg->getType(); + QualType CallTy = Msg->getArg(0)->getType(); + + // Check for the easy case, the literal maps directly to the call. + if (Ctx.hasSameType(ArgTy, CallTy)) { + commit.replaceWithInner(Msg->getSourceRange(), ArgRange); + commit.insert(ArgRange.getBegin(), "@"); + return true; + } + + // We will need to modify the literal suffix to get the same type as the call. + // Don't even try if it came from a macro. + if (ArgRange.getBegin().isMacroID()) + return false; + + bool LitIsFloat = ArgTy->isFloatingType(); + // For a float passed to integer call, don't try rewriting. It is difficult + // and a very uncommon case anyway. + if (LitIsFloat && !CallIsFloating) + return false; + + // Try to modify the literal make it the same type as the method call. + // -Modify the suffix, and/or + // -Change integer to float + + LiteralInfo LitInfo; + bool isIntZero = false; + if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE)) + isIntZero = !IntE->getValue().getBoolValue(); + if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo)) + return false; + + // Not easy to do int -> float with hex/octal and uncommon anyway. + if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal)) + return false; + + SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin(); + SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd(); + + commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()), + LitInfo.WithoutSuffRange); + commit.insert(LitB, "@"); + + if (!LitIsFloat && CallIsFloating) + commit.insert(LitE, ".0"); + + if (CallIsFloating) { + if (!CallIsDouble) + commit.insert(LitE, LitInfo.F); + } else { + if (CallIsUnsigned) + commit.insert(LitE, LitInfo.U); + + if (CallIsLong) + commit.insert(LitE, LitInfo.L); + else if (CallIsLongLong) + commit.insert(LitE, LitInfo.LL); + } + return true; +} diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 43ac4752112..9391eea32d0 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -428,6 +428,7 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::RewriteObjC: return "-rewrite-objc"; case frontend::RewriteTest: return "-rewrite-test"; case frontend::RunAnalysis: return "-analyze"; + case frontend::MigrateSource: return "-migrate"; case frontend::RunPreprocessorOnly: return "-Eonly"; } @@ -483,9 +484,9 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-arcmt-migrate"); break; } - if (!Opts.ARCMTMigrateDir.empty()) { - Res.push_back("-arcmt-migrate-directory"); - Res.push_back(Opts.ARCMTMigrateDir); + if (!Opts.MTMigrateDir.empty()) { + Res.push_back("-mt-migrate-directory"); + Res.push_back(Opts.MTMigrateDir); } if (!Opts.ARCMTMigrateReportOut.empty()) { Res.push_back("-arcmt-migrate-report-output"); @@ -494,6 +495,11 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, if (Opts.ARCMTMigrateEmitARCErrors) Res.push_back("-arcmt-migrate-emit-errors"); + if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Literals) + Res.push_back("-objcmt-migrate-literals"); + if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Subscripting) + Res.push_back("-objcmt-migrate-subscripting"); + bool NeedLang = false; for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].File) != @@ -828,6 +834,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fdebugger-support"); if (Opts.DebuggerCastResultToId) Res.push_back("-fdebugger-cast-result-to-id"); + if (Opts.DebuggerObjCLiteral) + Res.push_back("-fdebugger-objc-literal"); if (Opts.DelayedTemplateParsing) Res.push_back("-fdelayed-template-parsing"); if (Opts.Deprecated) @@ -1376,6 +1384,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::RewriteTest; break; case OPT_analyze: Opts.ProgramAction = frontend::RunAnalysis; break; + case OPT_migrate: + Opts.ProgramAction = frontend::MigrateSource; break; case OPT_Eonly: Opts.ProgramAction = frontend::RunPreprocessorOnly; break; } @@ -1432,7 +1442,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp); Opts.OverrideRecordLayoutsFile = Args.getLastArgValue(OPT_foverride_record_layout_EQ); - Opts.ARCMTAction = FrontendOptions::ARCMT_None; if (const Arg *A = Args.getLastArg(OPT_arcmt_check, OPT_arcmt_modify, OPT_arcmt_migrate)) { @@ -1450,12 +1459,23 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, break; } } - Opts.ARCMTMigrateDir = Args.getLastArgValue(OPT_arcmt_migrate_directory); + Opts.MTMigrateDir = Args.getLastArgValue(OPT_mt_migrate_directory); Opts.ARCMTMigrateReportOut = Args.getLastArgValue(OPT_arcmt_migrate_report_output); Opts.ARCMTMigrateEmitARCErrors = Args.hasArg(OPT_arcmt_migrate_emit_arc_errors); + if (Args.hasArg(OPT_objcmt_migrate_literals)) + Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Literals; + if (Args.hasArg(OPT_objcmt_migrate_subscripting)) + Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Subscripting; + + if (Opts.ARCMTAction != FrontendOptions::ARCMT_None && + Opts.ObjCMTAction != FrontendOptions::ObjCMT_None) { + Diags.Report(diag::err_drv_argument_not_allowed_with) + << "ARC migration" << "ObjC migration"; + } + InputKind DashX = IK_None; if (const Arg *A = Args.getLastArg(OPT_x)) { DashX = llvm::StringSwitch<InputKind>(A->getValue(Args)) @@ -1899,6 +1919,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.ParseUnknownAnytype = Args.hasArg(OPT_funknown_anytype); Opts.DebuggerSupport = Args.hasArg(OPT_fdebugger_support); Opts.DebuggerCastResultToId = Args.hasArg(OPT_fdebugger_cast_result_to_id); + Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal); Opts.AddressSanitizer = Args.hasArg(OPT_faddress_sanitizer); Opts.ThreadSanitizer = Args.hasArg(OPT_fthread_sanitizer); Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack); diff --git a/clang/lib/Frontend/DiagnosticRenderer.cpp b/clang/lib/Frontend/DiagnosticRenderer.cpp index 29f9ed5a7d4..6c3bb1d6953 100644 --- a/clang/lib/Frontend/DiagnosticRenderer.cpp +++ b/clang/lib/Frontend/DiagnosticRenderer.cpp @@ -12,6 +12,9 @@ #include "clang/Basic/SourceManager.h" #include "clang/Frontend/DiagnosticOptions.h" #include "clang/Lex/Lexer.h" +#include "clang/Edit/EditedSource.h" +#include "clang/Edit/Commit.h" +#include "clang/Edit/EditsReceiver.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" @@ -127,6 +130,54 @@ DiagnosticRenderer::DiagnosticRenderer(const SourceManager &SM, DiagnosticRenderer::~DiagnosticRenderer() {} +namespace { + +class FixitReceiver : public edit::EditsReceiver { + SmallVectorImpl<FixItHint> &MergedFixits; + +public: + FixitReceiver(SmallVectorImpl<FixItHint> &MergedFixits) + : MergedFixits(MergedFixits) { } + virtual void insert(SourceLocation loc, StringRef text) { + MergedFixits.push_back(FixItHint::CreateInsertion(loc, text)); + } + virtual void replace(CharSourceRange range, StringRef text) { + MergedFixits.push_back(FixItHint::CreateReplacement(range, text)); + } +}; + +} + +static void mergeFixits(ArrayRef<FixItHint> FixItHints, + const SourceManager &SM, const LangOptions &LangOpts, + SmallVectorImpl<FixItHint> &MergedFixits) { + edit::Commit commit(SM, LangOpts); + for (ArrayRef<FixItHint>::const_iterator + I = FixItHints.begin(), E = FixItHints.end(); I != E; ++I) { + const FixItHint &Hint = *I; + 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); + } + } + + edit::EditedSource Editor(SM, LangOpts); + if (Editor.commit(commit)) { + FixitReceiver Rec(MergedFixits); + Editor.applyRewrites(Rec); + } +} void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level, @@ -152,6 +203,12 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(), Ranges.end()); + llvm::SmallVector<FixItHint, 8> MergedFixits; + if (!FixItHints.empty()) { + mergeFixits(FixItHints, SM, LangOpts, MergedFixits); + FixItHints = MergedFixits; + } + for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(), E = FixItHints.end(); I != E; ++I) diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 0841b2cef81..07d2b8d19f2 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -76,6 +76,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { case RewriteObjC: return new RewriteObjCAction(); case RewriteTest: return new RewriteTestAction(); case RunAnalysis: return new ento::AnalysisAction(); + case MigrateSource: return new arcmt::MigrateSourceAction(); case RunPreprocessorOnly: return new PreprocessOnlyAction(); } llvm_unreachable("Invalid program action!"); @@ -105,12 +106,18 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { break; case FrontendOptions::ARCMT_Migrate: Act = new arcmt::MigrateAction(Act, - FEOpts.ARCMTMigrateDir, + FEOpts.MTMigrateDir, FEOpts.ARCMTMigrateReportOut, FEOpts.ARCMTMigrateEmitARCErrors); break; } + if (FEOpts.ObjCMTAction != FrontendOptions::ObjCMT_None) { + Act = new arcmt::ObjCMigrateAction(Act, FEOpts.MTMigrateDir, + FEOpts.ObjCMTAction & ~FrontendOptions::ObjCMT_Literals, + FEOpts.ObjCMTAction & ~FrontendOptions::ObjCMT_Subscripting); + } + // If there are any AST files to merge, create a frontend action // adaptor to perform the merge. if (!FEOpts.ASTMergeFiles.empty()) diff --git a/clang/lib/Makefile b/clang/lib/Makefile index 74df7abcef2..69c5cd5d830 100755 --- a/clang/lib/Makefile +++ b/clang/lib/Makefile @@ -9,7 +9,7 @@ CLANG_LEVEL := .. PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \ - StaticAnalyzer Rewrite ARCMigrate Serialization Frontend \ + StaticAnalyzer Edit Rewrite ARCMigrate Serialization Frontend \ FrontendTool Index Driver include $(CLANG_LEVEL)/Makefile diff --git a/clang/lib/Rewrite/FixItRewriter.cpp b/clang/lib/Rewrite/FixItRewriter.cpp index caa7d06ac2e..3863adb4f16 100644 --- a/clang/lib/Rewrite/FixItRewriter.cpp +++ b/clang/lib/Rewrite/FixItRewriter.cpp @@ -14,6 +14,8 @@ //===----------------------------------------------------------------------===// #include "clang/Rewrite/FixItRewriter.h" +#include "clang/Edit/Commit.h" +#include "clang/Edit/EditsReceiver.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" @@ -29,6 +31,7 @@ FixItRewriter::FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const LangOptions &LangOpts, FixItOptions *FixItOpts) : Diags(Diags), + Editor(SourceMgr, LangOpts), Rewrite(SourceMgr, LangOpts), FixItOpts(FixItOpts), NumFailures(0), @@ -51,6 +54,24 @@ bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) { 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) { @@ -58,6 +79,9 @@ bool FixItRewriter::WriteFixedFiles( 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; @@ -116,16 +140,28 @@ void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, // Make sure that we can perform all of the modifications we // in this diagnostic. - bool CanRewrite = Info.getNumFixItHints() > 0; + edit::Commit commit(Editor); for (unsigned Idx = 0, Last = Info.getNumFixItHints(); Idx < Last; ++Idx) { const FixItHint &Hint = Info.getFixItHint(Idx); - if (Hint.RemoveRange.isValid() && - Rewrite.getRangeSize(Hint.RemoveRange) == -1) { - CanRewrite = false; - break; + + 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) @@ -138,27 +174,8 @@ void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, } return; } - - bool Failed = false; - for (unsigned Idx = 0, Last = Info.getNumFixItHints(); - Idx < Last; ++Idx) { - const FixItHint &Hint = Info.getFixItHint(Idx); - - if (Hint.CodeToInsert.empty()) { - // We're removing code. - if (Rewrite.RemoveText(Hint.RemoveRange)) - Failed = true; - continue; - } - - // We're replacing code. - if (Rewrite.ReplaceText(Hint.RemoveRange.getBegin(), - Rewrite.getRangeSize(Hint.RemoveRange), - Hint.CodeToInsert)) - Failed = true; - } - - if (Failed) { + + if (!Editor.commit(commit)) { ++NumFailures; Diag(Info.getLocation(), diag::note_fixit_failed); return; diff --git a/clang/test/ARCMT/dispatch.m b/clang/test/ARCMT/dispatch.m new file mode 100644 index 00000000000..75c4a83459c --- /dev/null +++ b/clang/test/ARCMT/dispatch.m @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result +// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -x objective-c %s > %t +// RUN: diff %t %s.result + +#include "Common.h" + +#define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; }) +#define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; }) +#define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; }) +#define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; }) + +typedef id dispatch_object_t; +typedef id xpc_object_t; + +void _dispatch_object_validate(dispatch_object_t object); +void _xpc_object_validate(xpc_object_t object); + +dispatch_object_t getme(void); + +void func(dispatch_object_t o) { + dispatch_retain(o); + dispatch_release(o); + dispatch_retain(getme()); +} + +void func2(xpc_object_t o) { + xpc_retain(o); + xpc_release(o); +} diff --git a/clang/test/ARCMT/dispatch.m.result b/clang/test/ARCMT/dispatch.m.result new file mode 100644 index 00000000000..e897672a264 --- /dev/null +++ b/clang/test/ARCMT/dispatch.m.result @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result +// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -x objective-c %s > %t +// RUN: diff %t %s.result + +#include "Common.h" + +#define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; }) +#define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; }) +#define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; }) +#define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; }) + +typedef id dispatch_object_t; +typedef id xpc_object_t; + +void _dispatch_object_validate(dispatch_object_t object); +void _xpc_object_validate(xpc_object_t object); + +dispatch_object_t getme(void); + +void func(dispatch_object_t o) { + getme(); +} + +void func2(xpc_object_t o) { +} diff --git a/clang/test/ARCMT/driver-migrate.m b/clang/test/ARCMT/driver-migrate.m index a2b1a7dc27a..a912ad95b15 100644 --- a/clang/test/ARCMT/driver-migrate.m +++ b/clang/test/ARCMT/driver-migrate.m @@ -1,6 +1,6 @@ // RUN: %clang -### -ccc-arcmt-migrate /foo/bar -fsyntax-only %s 2>&1 | FileCheck %s -// CHECK: "-arcmt-migrate" "-arcmt-migrate-directory" "{{[^"]*}}/foo/bar" +// CHECK: "-arcmt-migrate" "-mt-migrate-directory" "{{[^"]*}}/foo/bar" // RUN: touch %t.o // RUN: %clang -ccc-arcmt-check -target i386-apple-darwin9 -### %t.o 2> %t.log diff --git a/clang/test/ARCMT/migrate-emit-errors.m b/clang/test/ARCMT/migrate-emit-errors.m index 6a4a3963ca0..95c0d2f8f07 100644 --- a/clang/test/ARCMT/migrate-emit-errors.m +++ b/clang/test/ARCMT/migrate-emit-errors.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -arcmt-migrate-emit-errors %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t -arcmt-migrate-emit-errors %s 2>&1 | FileCheck %s // RUN: rm -rf %t @protocol NSObject diff --git a/clang/test/ARCMT/migrate-plist-output.m b/clang/test/ARCMT/migrate-plist-output.m index b9e3ceff864..12efa93f075 100644 --- a/clang/test/ARCMT/migrate-plist-output.m +++ b/clang/test/ARCMT/migrate-plist-output.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t.dir -arcmt-migrate-report-output %t.plist %s +// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t.dir -arcmt-migrate-report-output %t.plist %s // RUN: FileCheck %s -input-file=%t.plist // RUN: rm -rf %t.dir diff --git a/clang/test/ARCMT/migrate-space-in-path.m b/clang/test/ARCMT/migrate-space-in-path.m index e454fae642f..89dfe1475cf 100644 --- a/clang/test/ARCMT/migrate-space-in-path.m +++ b/clang/test/ARCMT/migrate-space-in-path.m @@ -1,6 +1,6 @@ // RUN: rm -rf %t.migrate -// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t.migrate %S/"with space"/test1.m.in -x objective-c -// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t.migrate %S/"with space"/test2.m.in -x objective-c -// RUN: c-arcmt-test -arcmt-migrate-directory %t.migrate | arcmt-test -verify-transformed-files %S/"with space"/test1.m.in.result %S/"with space"/test2.m.in.result %S/"with space"/test.h.result +// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t.migrate %S/"with space"/test1.m.in -x objective-c +// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t.migrate %S/"with space"/test2.m.in -x objective-c +// RUN: c-arcmt-test -mt-migrate-directory %t.migrate | arcmt-test -verify-transformed-files %S/"with space"/test1.m.in.result %S/"with space"/test2.m.in.result %S/"with space"/test.h.result // RUN: rm -rf %t.migrate // DISABLE: mingw32 diff --git a/clang/test/ARCMT/migrate.m b/clang/test/ARCMT/migrate.m index beaf8e5b152..6f41258e59d 100644 --- a/clang/test/ARCMT/migrate.m +++ b/clang/test/ARCMT/migrate.m @@ -1,6 +1,6 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test1.m.in -x objective-c -// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test2.m.in -x objective-c -// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %S/Inputs/test1.m.in.result %S/Inputs/test2.m.in.result %S/Inputs/test.h.result +// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t %S/Inputs/test1.m.in -x objective-c +// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t %S/Inputs/test2.m.in -x objective-c +// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %S/Inputs/test1.m.in.result %S/Inputs/test2.m.in.result %S/Inputs/test.h.result // RUN: rm -rf %t // DISABLE: mingw32 diff --git a/clang/test/ARCMT/objcmt-numeric-literals.m b/clang/test/ARCMT/objcmt-numeric-literals.m new file mode 100644 index 00000000000..b86af4d056a --- /dev/null +++ b/clang/test/ARCMT/objcmt-numeric-literals.m @@ -0,0 +1,501 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c++ +// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result + +#define YES __objc_yes +#define NO __objc_no + +typedef long NSInteger; +typedef unsigned long NSUInteger; +typedef signed char BOOL; +#define nil ((void*) 0) + +@interface NSObject ++ (id)alloc; +@end + +@interface NSNumber : NSObject +@end + +@interface NSNumber (NSNumberCreation) +- (id)initWithChar:(char)value; +- (id)initWithUnsignedChar:(unsigned char)value; +- (id)initWithShort:(short)value; +- (id)initWithUnsignedShort:(unsigned short)value; +- (id)initWithInt:(int)value; +- (id)initWithUnsignedInt:(unsigned int)value; +- (id)initWithLong:(long)value; +- (id)initWithUnsignedLong:(unsigned long)value; +- (id)initWithLongLong:(long long)value; +- (id)initWithUnsignedLongLong:(unsigned long long)value; +- (id)initWithFloat:(float)value; +- (id)initWithDouble:(double)value; +- (id)initWithBool:(BOOL)value; +- (id)initWithInteger:(NSInteger)value; +- (id)initWithUnsignedInteger:(NSUInteger)value; + ++ (NSNumber *)numberWithChar:(char)value; ++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value; ++ (NSNumber *)numberWithShort:(short)value; ++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value; ++ (NSNumber *)numberWithInt:(int)value; ++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value; ++ (NSNumber *)numberWithLong:(long)value; ++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value; ++ (NSNumber *)numberWithLongLong:(long long)value; ++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value; ++ (NSNumber *)numberWithFloat:(float)value; ++ (NSNumber *)numberWithDouble:(double)value; ++ (NSNumber *)numberWithBool:(BOOL)value; ++ (NSNumber *)numberWithInteger:(NSInteger)value; ++ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value; +@end + +#define VAL_INT 2 +#define VAL_UINT 2U +#define VAL_CHAR 'a' + +void foo() { + [NSNumber numberWithChar:'a']; + [NSNumber numberWithChar:L'a']; + [NSNumber numberWithChar:2]; + [NSNumber numberWithChar:2U]; + [NSNumber numberWithChar:2u]; + [NSNumber numberWithChar:2L]; + [NSNumber numberWithChar:2l]; + [NSNumber numberWithChar:2LL]; + [NSNumber numberWithChar:2ll]; + [NSNumber numberWithChar:2ul]; + [NSNumber numberWithChar:2lu]; + [NSNumber numberWithChar:2ull]; + [NSNumber numberWithChar:2llu]; + [NSNumber numberWithChar:2.0]; + [NSNumber numberWithChar:2.0f]; + [NSNumber numberWithChar:2.0F]; + [NSNumber numberWithChar:2.0l]; + [NSNumber numberWithChar:2.0L]; + [NSNumber numberWithChar:0x2f]; + [NSNumber numberWithChar:04]; + [NSNumber numberWithChar:0]; + [NSNumber numberWithChar:0.0]; + [NSNumber numberWithChar:YES]; + [NSNumber numberWithChar:NO]; + [NSNumber numberWithChar:true]; + [NSNumber numberWithChar:false]; + [NSNumber numberWithChar:VAL_INT]; + [NSNumber numberWithChar:VAL_UINT]; + [NSNumber numberWithChar:VAL_CHAR]; + + [NSNumber numberWithUnsignedChar:'a']; + [NSNumber numberWithUnsignedChar:L'a']; + [NSNumber numberWithUnsignedChar:2]; + [NSNumber numberWithUnsignedChar:2U]; + [NSNumber numberWithUnsignedChar:2u]; + [NSNumber numberWithUnsignedChar:2L]; + [NSNumber numberWithUnsignedChar:2l]; + [NSNumber numberWithUnsignedChar:2LL]; + [NSNumber numberWithUnsignedChar:2ll]; + [NSNumber numberWithUnsignedChar:2ul]; + [NSNumber numberWithUnsignedChar:2lu]; + [NSNumber numberWithUnsignedChar:2ull]; + [NSNumber numberWithUnsignedChar:2llu]; + [NSNumber numberWithUnsignedChar:2.0]; + [NSNumber numberWithUnsignedChar:2.0f]; + [NSNumber numberWithUnsignedChar:2.0F]; + [NSNumber numberWithUnsignedChar:2.0l]; + [NSNumber numberWithUnsignedChar:2.0L]; + [NSNumber numberWithUnsignedChar:0x2f]; + [NSNumber numberWithUnsignedChar:04]; + [NSNumber numberWithUnsignedChar:0]; + [NSNumber numberWithUnsignedChar:0.0]; + [NSNumber numberWithUnsignedChar:YES]; + [NSNumber numberWithUnsignedChar:NO]; + [NSNumber numberWithUnsignedChar:true]; + [NSNumber numberWithUnsignedChar:false]; + [NSNumber numberWithUnsignedChar:VAL_INT]; + [NSNumber numberWithUnsignedChar:VAL_UINT]; + [NSNumber numberWithUnsignedChar:VAL_CHAR]; + + [NSNumber numberWithShort:'a']; + [NSNumber numberWithShort:L'a']; + [NSNumber numberWithShort:2]; + [NSNumber numberWithShort:2U]; + [NSNumber numberWithShort:2u]; + [NSNumber numberWithShort:2L]; + [NSNumber numberWithShort:2l]; + [NSNumber numberWithShort:2LL]; + [NSNumber numberWithShort:2ll]; + [NSNumber numberWithShort:2ul]; + [NSNumber numberWithShort:2lu]; + [NSNumber numberWithShort:2ull]; + [NSNumber numberWithShort:2llu]; + [NSNumber numberWithShort:2.0]; + [NSNumber numberWithShort:2.0f]; + [NSNumber numberWithShort:2.0F]; + [NSNumber numberWithShort:2.0l]; + [NSNumber numberWithShort:2.0L]; + [NSNumber numberWithShort:0x2f]; + [NSNumber numberWithShort:04]; + [NSNumber numberWithShort:0]; + [NSNumber numberWithShort:0.0]; + [NSNumber numberWithShort:YES]; + [NSNumber numberWithShort:NO]; + [NSNumber numberWithShort:true]; + [NSNumber numberWithShort:false]; + [NSNumber numberWithShort:VAL_INT]; + [NSNumber numberWithShort:VAL_UINT]; + + [NSNumber numberWithUnsignedShort:'a']; + [NSNumber numberWithUnsignedShort:L'a']; + [NSNumber numberWithUnsignedShort:2]; + [NSNumber numberWithUnsignedShort:2U]; + [NSNumber numberWithUnsignedShort:2u]; + [NSNumber numberWithUnsignedShort:2L]; + [NSNumber numberWithUnsignedShort:2l]; + [NSNumber numberWithUnsignedShort:2LL]; + [NSNumber numberWithUnsignedShort:2ll]; + [NSNumber numberWithUnsignedShort:2ul]; + [NSNumber numberWithUnsignedShort:2lu]; + [NSNumber numberWithUnsignedShort:2ull]; + [NSNumber numberWithUnsignedShort:2llu]; + [NSNumber numberWithUnsignedShort:2.0]; + [NSNumber numberWithUnsignedShort:2.0f]; + [NSNumber numberWithUnsignedShort:2.0F]; + [NSNumber numberWithUnsignedShort:2.0l]; + [NSNumber numberWithUnsignedShort:2.0L]; + [NSNumber numberWithUnsignedShort:0x2f]; + [NSNumber numberWithUnsignedShort:04]; + [NSNumber numberWithUnsignedShort:0]; + [NSNumber numberWithUnsignedShort:0.0]; + [NSNumber numberWithUnsignedShort:YES]; + [NSNumber numberWithUnsignedShort:NO]; + [NSNumber numberWithUnsignedShort:true]; + [NSNumber numberWithUnsignedShort:false]; + [NSNumber numberWithUnsignedShort:VAL_INT]; + [NSNumber numberWithUnsignedShort:VAL_UINT]; + + [NSNumber numberWithInt:'a']; + [NSNumber numberWithInt:L'a']; + [NSNumber numberWithInt:2]; + [NSNumber numberWithInt:2U]; + [NSNumber numberWithInt:2u]; + [NSNumber numberWithInt:2L]; + [NSNumber numberWithInt:2l]; + [NSNumber numberWithInt:2LL]; + [NSNumber numberWithInt:2ll]; + [NSNumber numberWithInt:2ul]; + [NSNumber numberWithInt:2lu]; + [NSNumber numberWithInt:2ull]; + [NSNumber numberWithInt:2llu]; + [NSNumber numberWithInt:2.0]; + [NSNumber numberWithInt:2.0f]; + [NSNumber numberWithInt:2.0F]; + [NSNumber numberWithInt:2.0l]; + [NSNumber numberWithInt:2.0L]; + [NSNumber numberWithInt:0x2f]; + [NSNumber numberWithInt:04]; + [NSNumber numberWithInt:0]; + [NSNumber numberWithInt:0.0]; + [NSNumber numberWithInt:YES]; + [NSNumber numberWithInt:NO]; + [NSNumber numberWithInt:true]; + [NSNumber numberWithInt:false]; + [NSNumber numberWithInt:VAL_INT]; + [NSNumber numberWithInt:VAL_UINT]; + + (void)[[NSNumber alloc] initWithInt:2]; + (void)[[NSNumber alloc] initWithInt:2U]; + + [NSNumber numberWithInt:+2]; + [NSNumber numberWithInt:-2]; + + [NSNumber numberWithUnsignedInt:'a']; + [NSNumber numberWithUnsignedInt:L'a']; + [NSNumber numberWithUnsignedInt:2]; + [NSNumber numberWithUnsignedInt:2U]; + [NSNumber numberWithUnsignedInt:2u]; + [NSNumber numberWithUnsignedInt:2L]; + [NSNumber numberWithUnsignedInt:2l]; + [NSNumber numberWithUnsignedInt:2LL]; + [NSNumber numberWithUnsignedInt:2ll]; + [NSNumber numberWithUnsignedInt:2ul]; + [NSNumber numberWithUnsignedInt:2lu]; + [NSNumber numberWithUnsignedInt:2ull]; + [NSNumber numberWithUnsignedInt:2llu]; + [NSNumber numberWithUnsignedInt:2.0]; + [NSNumber numberWithUnsignedInt:2.0f]; + [NSNumber numberWithUnsignedInt:2.0F]; + [NSNumber numberWithUnsignedInt:2.0l]; + [NSNumber numberWithUnsignedInt:2.0L]; + [NSNumber numberWithUnsignedInt:0x2f]; + [NSNumber numberWithUnsignedInt:04]; + [NSNumber numberWithUnsignedInt:0]; + [NSNumber numberWithUnsignedInt:0.0]; + [NSNumber numberWithUnsignedInt:YES]; + [NSNumber numberWithUnsignedInt:NO]; + [NSNumber numberWithUnsignedInt:true]; + [NSNumber numberWithUnsignedInt:false]; + [NSNumber numberWithUnsignedInt:VAL_INT]; + [NSNumber numberWithUnsignedInt:VAL_UINT]; + + [NSNumber numberWithLong:'a']; + [NSNumber numberWithLong:L'a']; + [NSNumber numberWithLong:2]; + [NSNumber numberWithLong:2U]; + [NSNumber numberWithLong:2u]; + [NSNumber numberWithLong:2L]; + [NSNumber numberWithLong:2l]; + [NSNumber numberWithLong:2LL]; + [NSNumber numberWithLong:2ll]; + [NSNumber numberWithLong:2ul]; + [NSNumber numberWithLong:2lu]; + [NSNumber numberWithLong:2ull]; + [NSNumber numberWithLong:2llu]; + [NSNumber numberWithLong:2.0]; + [NSNumber numberWithLong:2.0f]; + [NSNumber numberWithLong:2.0F]; + [NSNumber numberWithLong:2.0l]; + [NSNumber numberWithLong:2.0L]; + [NSNumber numberWithLong:0x2f]; + [NSNumber numberWithLong:04]; + [NSNumber numberWithLong:0]; + [NSNumber numberWithLong:0.0]; + [NSNumber numberWithLong:YES]; + [NSNumber numberWithLong:NO]; + [NSNumber numberWithLong:true]; + [NSNumber numberWithLong:false]; + [NSNumber numberWithLong:VAL_INT]; + [NSNumber numberWithLong:VAL_UINT]; + + [NSNumber numberWithUnsignedLong:'a']; + [NSNumber numberWithUnsignedLong:L'a']; + [NSNumber numberWithUnsignedLong:2]; + [NSNumber numberWithUnsignedLong:2U]; + [NSNumber numberWithUnsignedLong:2u]; + [NSNumber numberWithUnsignedLong:2L]; + [NSNumber numberWithUnsignedLong:2l]; + [NSNumber numberWithUnsignedLong:2LL]; + [NSNumber numberWithUnsignedLong:2ll]; + [NSNumber numberWithUnsignedLong:2ul]; + [NSNumber numberWithUnsignedLong:2lu]; + [NSNumber numberWithUnsignedLong:2ull]; + [NSNumber numberWithUnsignedLong:2llu]; + [NSNumber numberWithUnsignedLong:2.0]; + [NSNumber numberWithUnsignedLong:2.0f]; + [NSNumber numberWithUnsignedLong:2.0F]; + [NSNumber numberWithUnsignedLong:2.0l]; + [NSNumber numberWithUnsignedLong:2.0L]; + [NSNumber numberWithUnsignedLong:0x2f]; + [NSNumber numberWithUnsignedLong:04]; + [NSNumber numberWithUnsignedLong:0]; + [NSNumber numberWithUnsignedLong:0.0]; + [NSNumber numberWithUnsignedLong:YES]; + [NSNumber numberWithUnsignedLong:NO]; + [NSNumber numberWithUnsignedLong:true]; + [NSNumber numberWithUnsignedLong:false]; + [NSNumber numberWithUnsignedLong:VAL_INT]; + [NSNumber numberWithUnsignedLong:VAL_UINT]; + + [NSNumber numberWithLongLong:'a']; + [NSNumber numberWithLongLong:L'a']; + [NSNumber numberWithLongLong:2]; + [NSNumber numberWithLongLong:2U]; + [NSNumber numberWithLongLong:2u]; + [NSNumber numberWithLongLong:2L]; + [NSNumber numberWithLongLong:2l]; + [NSNumber numberWithLongLong:2LL]; + [NSNumber numberWithLongLong:2ll]; + [NSNumber numberWithLongLong:2ul]; + [NSNumber numberWithLongLong:2lu]; + [NSNumber numberWithLongLong:2ull]; + [NSNumber numberWithLongLong:2llu]; + [NSNumber numberWithLongLong:2.0]; + [NSNumber numberWithLongLong:2.0f]; + [NSNumber numberWithLongLong:2.0F]; + [NSNumber numberWithLongLong:2.0l]; + [NSNumber numberWithLongLong:2.0L]; + [NSNumber numberWithLongLong:0x2f]; + [NSNumber numberWithLongLong:04]; + [NSNumber numberWithLongLong:0]; + [NSNumber numberWithLongLong:0.0]; + [NSNumber numberWithLongLong:YES]; + [NSNumber numberWithLongLong:NO]; + [NSNumber numberWithLongLong:true]; + [NSNumber numberWithLongLong:false]; + [NSNumber numberWithLongLong:VAL_INT]; + [NSNumber numberWithLongLong:VAL_UINT]; + + [NSNumber numberWithUnsignedLongLong:'a']; + [NSNumber numberWithUnsignedLongLong:L'a']; + [NSNumber numberWithUnsignedLongLong:2]; + [NSNumber numberWithUnsignedLongLong:2U]; + [NSNumber numberWithUnsignedLongLong:2u]; + [NSNumber numberWithUnsignedLongLong:2L]; + [NSNumber numberWithUnsignedLongLong:2l]; + [NSNumber numberWithUnsignedLongLong:2LL]; + [NSNumber numberWithUnsignedLongLong:2ll]; + [NSNumber numberWithUnsignedLongLong:2ul]; + [NSNumber numberWithUnsignedLongLong:2lu]; + [NSNumber numberWithUnsignedLongLong:2ull]; + [NSNumber numberWithUnsignedLongLong:2llu]; + [NSNumber numberWithUnsignedLongLong:2.0]; + [NSNumber numberWithUnsignedLongLong:2.0f]; + [NSNumber numberWithUnsignedLongLong:2.0F]; + [NSNumber numberWithUnsignedLongLong:2.0l]; + [NSNumber numberWithUnsignedLongLong:2.0L]; + [NSNumber numberWithUnsignedLongLong:0x2f]; + [NSNumber numberWithUnsignedLongLong:04]; + [NSNumber numberWithUnsignedLongLong:0]; + [NSNumber numberWithUnsignedLongLong:0.0]; + [NSNumber numberWithUnsignedLongLong:YES]; + [NSNumber numberWithUnsignedLongLong:NO]; + [NSNumber numberWithUnsignedLongLong:true]; + [NSNumber numberWithUnsignedLongLong:false]; + [NSNumber numberWithUnsignedLongLong:VAL_INT]; + [NSNumber numberWithUnsignedLongLong:VAL_UINT]; + + [NSNumber numberWithFloat:'a']; + [NSNumber numberWithFloat:L'a']; + [NSNumber numberWithFloat:2]; + [NSNumber numberWithFloat:2U]; + [NSNumber numberWithFloat:2u]; + [NSNumber numberWithFloat:2L]; + [NSNumber numberWithFloat:2l]; + [NSNumber numberWithFloat:2LL]; + [NSNumber numberWithFloat:2ll]; + [NSNumber numberWithFloat:2ul]; + [NSNumber numberWithFloat:2lu]; + [NSNumber numberWithFloat:2ull]; + [NSNumber numberWithFloat:2llu]; + [NSNumber numberWithFloat:2.0]; + [NSNumber numberWithFloat:2.0f]; + [NSNumber numberWithFloat:2.0F]; + [NSNumber numberWithFloat:2.0l]; + [NSNumber numberWithFloat:2.0L]; + [NSNumber numberWithFloat:0x2f]; + [NSNumber numberWithFloat:04]; + [NSNumber numberWithFloat:0]; + [NSNumber numberWithFloat:0.0]; + [NSNumber numberWithFloat:YES]; + [NSNumber numberWithFloat:NO]; + [NSNumber numberWithFloat:true]; + [NSNumber numberWithFloat:false]; + [NSNumber numberWithFloat:VAL_INT]; + [NSNumber numberWithFloat:VAL_UINT]; + + [NSNumber numberWithDouble:'a']; + [NSNumber numberWithDouble:L'a']; + [NSNumber numberWithDouble:2]; + [NSNumber numberWithDouble:2U]; + [NSNumber numberWithDouble:2u]; + [NSNumber numberWithDouble:2L]; + [NSNumber numberWithDouble:2l]; + [NSNumber numberWithDouble:2LL]; + [NSNumber numberWithDouble:2ll]; + [NSNumber numberWithDouble:2ul]; + [NSNumber numberWithDouble:2lu]; + [NSNumber numberWithDouble:2ull]; + [NSNumber numberWithDouble:2llu]; + [NSNumber numberWithDouble:2.0]; + [NSNumber numberWithDouble:2.0f]; + [NSNumber numberWithDouble:2.0F]; + [NSNumber numberWithDouble:2.0l]; + [NSNumber numberWithDouble:2.0L]; + [NSNumber numberWithDouble:0x2f]; + [NSNumber numberWithDouble:04]; + [NSNumber numberWithDouble:0]; + [NSNumber numberWithDouble:0.0]; + [NSNumber numberWithDouble:YES]; + [NSNumber numberWithDouble:NO]; + [NSNumber numberWithDouble:true]; + [NSNumber numberWithDouble:false]; + [NSNumber numberWithDouble:VAL_INT]; + [NSNumber numberWithDouble:VAL_UINT]; + + [NSNumber numberWithBool:'a']; + [NSNumber numberWithBool:L'a']; + [NSNumber numberWithBool:2]; + [NSNumber numberWithBool:2U]; + [NSNumber numberWithBool:2u]; + [NSNumber numberWithBool:2L]; + [NSNumber numberWithBool:2l]; + [NSNumber numberWithBool:2LL]; + [NSNumber numberWithBool:2ll]; + [NSNumber numberWithBool:2ul]; + [NSNumber numberWithBool:2lu]; + [NSNumber numberWithBool:2ull]; + [NSNumber numberWithBool:2llu]; + [NSNumber numberWithBool:2.0]; + [NSNumber numberWithBool:2.0f]; + [NSNumber numberWithBool:2.0F]; + [NSNumber numberWithBool:2.0l]; + [NSNumber numberWithBool:2.0L]; + [NSNumber numberWithBool:0x2f]; + [NSNumber numberWithBool:04]; + [NSNumber numberWithBool:0]; + [NSNumber numberWithBool:0.0]; + [NSNumber numberWithBool:YES]; + [NSNumber numberWithBool:NO]; + [NSNumber numberWithBool:true]; + [NSNumber numberWithBool:false]; + [NSNumber numberWithBool:VAL_INT]; + [NSNumber numberWithBool:VAL_UINT]; + + [NSNumber numberWithInteger:'a']; + [NSNumber numberWithInteger:L'a']; + [NSNumber numberWithInteger:2]; + [NSNumber numberWithInteger:2U]; + [NSNumber numberWithInteger:2u]; + [NSNumber numberWithInteger:2L]; + [NSNumber numberWithInteger:2l]; + [NSNumber numberWithInteger:2LL]; + [NSNumber numberWithInteger:2ll]; + [NSNumber numberWithInteger:2ul]; + [NSNumber numberWithInteger:2lu]; + [NSNumber numberWithInteger:2ull]; + [NSNumber numberWithInteger:2llu]; + [NSNumber numberWithInteger:2.0]; + [NSNumber numberWithInteger:2.0f]; + [NSNumber numberWithInteger:2.0F]; + [NSNumber numberWithInteger:2.0l]; + [NSNumber numberWithInteger:2.0L]; + [NSNumber numberWithInteger:0x2f]; + [NSNumber numberWithInteger:04]; + [NSNumber numberWithInteger:0]; + [NSNumber numberWithInteger:0.0]; + [NSNumber numberWithInteger:YES]; + [NSNumber numberWithInteger:NO]; + [NSNumber numberWithInteger:true]; + [NSNumber numberWithInteger:false]; + [NSNumber numberWithInteger:VAL_INT]; + [NSNumber numberWithInteger:VAL_UINT]; + + [NSNumber numberWithUnsignedInteger:'a']; + [NSNumber numberWithUnsignedInteger:L'a']; + [NSNumber numberWithUnsignedInteger:2]; + [NSNumber numberWithUnsignedInteger:2U]; + [NSNumber numberWithUnsignedInteger:2u]; + [NSNumber numberWithUnsignedInteger:2L]; + [NSNumber numberWithUnsignedInteger:2l]; + [NSNumber numberWithUnsignedInteger:2LL]; + [NSNumber numberWithUnsignedInteger:2ll]; + [NSNumber numberWithUnsignedInteger:2ul]; + [NSNumber numberWithUnsignedInteger:2lu]; + [NSNumber numberWithUnsignedInteger:2ull]; + [NSNumber numberWithUnsignedInteger:2llu]; + [NSNumber numberWithUnsignedInteger:2.0]; + [NSNumber numberWithUnsignedInteger:2.0f]; + [NSNumber numberWithUnsignedInteger:2.0F]; + [NSNumber numberWithUnsignedInteger:2.0l]; + [NSNumber numberWithUnsignedInteger:2.0L]; + [NSNumber numberWithUnsignedInteger:0x2f]; + [NSNumber numberWithUnsignedInteger:04]; + [NSNumber numberWithUnsignedInteger:0]; + [NSNumber numberWithUnsignedInteger:0.0]; + [NSNumber numberWithUnsignedInteger:YES]; + [NSNumber numberWithUnsignedInteger:NO]; + [NSNumber numberWithUnsignedInteger:true]; + [NSNumber numberWithUnsignedInteger:false]; + [NSNumber numberWithUnsignedInteger:VAL_INT]; + [NSNumber numberWithUnsignedInteger:VAL_UINT]; +} diff --git a/clang/test/ARCMT/objcmt-numeric-literals.m.result b/clang/test/ARCMT/objcmt-numeric-literals.m.result new file mode 100644 index 00000000000..1c4187aaef5 --- /dev/null +++ b/clang/test/ARCMT/objcmt-numeric-literals.m.result @@ -0,0 +1,501 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c++ +// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result + +#define YES __objc_yes +#define NO __objc_no + +typedef long NSInteger; +typedef unsigned long NSUInteger; +typedef signed char BOOL; +#define nil ((void*) 0) + +@interface NSObject ++ (id)alloc; +@end + +@interface NSNumber : NSObject +@end + +@interface NSNumber (NSNumberCreation) +- (id)initWithChar:(char)value; +- (id)initWithUnsignedChar:(unsigned char)value; +- (id)initWithShort:(short)value; +- (id)initWithUnsignedShort:(unsigned short)value; +- (id)initWithInt:(int)value; +- (id)initWithUnsignedInt:(unsigned int)value; +- (id)initWithLong:(long)value; +- (id)initWithUnsignedLong:(unsigned long)value; +- (id)initWithLongLong:(long long)value; +- (id)initWithUnsignedLongLong:(unsigned long long)value; +- (id)initWithFloat:(float)value; +- (id)initWithDouble:(double)value; +- (id)initWithBool:(BOOL)value; +- (id)initWithInteger:(NSInteger)value; +- (id)initWithUnsignedInteger:(NSUInteger)value; + ++ (NSNumber *)numberWithChar:(char)value; ++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value; ++ (NSNumber *)numberWithShort:(short)value; ++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value; ++ (NSNumber *)numberWithInt:(int)value; ++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value; ++ (NSNumber *)numberWithLong:(long)value; ++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value; ++ (NSNumber *)numberWithLongLong:(long long)value; ++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value; ++ (NSNumber *)numberWithFloat:(float)value; ++ (NSNumber *)numberWithDouble:(double)value; ++ (NSNumber *)numberWithBool:(BOOL)value; ++ (NSNumber *)numberWithInteger:(NSInteger)value; ++ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value; +@end + +#define VAL_INT 2 +#define VAL_UINT 2U +#define VAL_CHAR 'a' + +void foo() { + @'a'; + [NSNumber numberWithChar:L'a']; + [NSNumber numberWithChar:2]; + [NSNumber numberWithChar:2U]; + [NSNumber numberWithChar:2u]; + [NSNumber numberWithChar:2L]; + [NSNumber numberWithChar:2l]; + [NSNumber numberWithChar:2LL]; + [NSNumber numberWithChar:2ll]; + [NSNumber numberWithChar:2ul]; + [NSNumber numberWithChar:2lu]; + [NSNumber numberWithChar:2ull]; + [NSNumber numberWithChar:2llu]; + [NSNumber numberWithChar:2.0]; + [NSNumber numberWithChar:2.0f]; + [NSNumber numberWithChar:2.0F]; + [NSNumber numberWithChar:2.0l]; + [NSNumber numberWithChar:2.0L]; + [NSNumber numberWithChar:0x2f]; + [NSNumber numberWithChar:04]; + [NSNumber numberWithChar:0]; + [NSNumber numberWithChar:0.0]; + [NSNumber numberWithChar:YES]; + [NSNumber numberWithChar:NO]; + [NSNumber numberWithChar:true]; + [NSNumber numberWithChar:false]; + [NSNumber numberWithChar:VAL_INT]; + [NSNumber numberWithChar:VAL_UINT]; + @VAL_CHAR; + + [NSNumber numberWithUnsignedChar:'a']; + [NSNumber numberWithUnsignedChar:L'a']; + [NSNumber numberWithUnsignedChar:2]; + [NSNumber numberWithUnsignedChar:2U]; + [NSNumber numberWithUnsignedChar:2u]; + [NSNumber numberWithUnsignedChar:2L]; + [NSNumber numberWithUnsignedChar:2l]; + [NSNumber numberWithUnsignedChar:2LL]; + [NSNumber numberWithUnsignedChar:2ll]; + [NSNumber numberWithUnsignedChar:2ul]; + [NSNumber numberWithUnsignedChar:2lu]; + [NSNumber numberWithUnsignedChar:2ull]; + [NSNumber numberWithUnsignedChar:2llu]; + [NSNumber numberWithUnsignedChar:2.0]; + [NSNumber numberWithUnsignedChar:2.0f]; + [NSNumber numberWithUnsignedChar:2.0F]; + [NSNumber numberWithUnsignedChar:2.0l]; + [NSNumber numberWithUnsignedChar:2.0L]; + [NSNumber numberWithUnsignedChar:0x2f]; + [NSNumber numberWithUnsignedChar:04]; + [NSNumber numberWithUnsignedChar:0]; + [NSNumber numberWithUnsignedChar:0.0]; + [NSNumber numberWithUnsignedChar:YES]; + [NSNumber numberWithUnsignedChar:NO]; + [NSNumber numberWithUnsignedChar:true]; + [NSNumber numberWithUnsignedChar:false]; + [NSNumber numberWithUnsignedChar:VAL_INT]; + [NSNumber numberWithUnsignedChar:VAL_UINT]; + [NSNumber numberWithUnsignedChar:VAL_CHAR]; + + [NSNumber numberWithShort:'a']; + [NSNumber numberWithShort:L'a']; + [NSNumber numberWithShort:2]; + [NSNumber numberWithShort:2U]; + [NSNumber numberWithShort:2u]; + [NSNumber numberWithShort:2L]; + [NSNumber numberWithShort:2l]; + [NSNumber numberWithShort:2LL]; + [NSNumber numberWithShort:2ll]; + [NSNumber numberWithShort:2ul]; + [NSNumber numberWithShort:2lu]; + [NSNumber numberWithShort:2ull]; + [NSNumber numberWithShort:2llu]; + [NSNumber numberWithShort:2.0]; + [NSNumber numberWithShort:2.0f]; + [NSNumber numberWithShort:2.0F]; + [NSNumber numberWithShort:2.0l]; + [NSNumber numberWithShort:2.0L]; + [NSNumber numberWithShort:0x2f]; + [NSNumber numberWithShort:04]; + [NSNumber numberWithShort:0]; + [NSNumber numberWithShort:0.0]; + [NSNumber numberWithShort:YES]; + [NSNumber numberWithShort:NO]; + [NSNumber numberWithShort:true]; + [NSNumber numberWithShort:false]; + [NSNumber numberWithShort:VAL_INT]; + [NSNumber numberWithShort:VAL_UINT]; + + [NSNumber numberWithUnsignedShort:'a']; + [NSNumber numberWithUnsignedShort:L'a']; + [NSNumber numberWithUnsignedShort:2]; + [NSNumber numberWithUnsignedShort:2U]; + [NSNumber numberWithUnsignedShort:2u]; + [NSNumber numberWithUnsignedShort:2L]; + [NSNumber numberWithUnsignedShort:2l]; + [NSNumber numberWithUnsignedShort:2LL]; + [NSNumber numberWithUnsignedShort:2ll]; + [NSNumber numberWithUnsignedShort:2ul]; + [NSNumber numberWithUnsignedShort:2lu]; + [NSNumber numberWithUnsignedShort:2ull]; + [NSNumber numberWithUnsignedShort:2llu]; + [NSNumber numberWithUnsignedShort:2.0]; + [NSNumber numberWithUnsignedShort:2.0f]; + [NSNumber numberWithUnsignedShort:2.0F]; + [NSNumber numberWithUnsignedShort:2.0l]; + [NSNumber numberWithUnsignedShort:2.0L]; + [NSNumber numberWithUnsignedShort:0x2f]; + [NSNumber numberWithUnsignedShort:04]; + [NSNumber numberWithUnsignedShort:0]; + [NSNumber numberWithUnsignedShort:0.0]; + [NSNumber numberWithUnsignedShort:YES]; + [NSNumber numberWithUnsignedShort:NO]; + [NSNumber numberWithUnsignedShort:true]; + [NSNumber numberWithUnsignedShort:false]; + [NSNumber numberWithUnsignedShort:VAL_INT]; + [NSNumber numberWithUnsignedShort:VAL_UINT]; + + [NSNumber numberWithInt:'a']; + [NSNumber numberWithInt:L'a']; + @2; + @2; + @2; + @2; + @2; + @2; + @2; + @2; + @2; + @2; + @2; + [NSNumber numberWithInt:2.0]; + [NSNumber numberWithInt:2.0f]; + [NSNumber numberWithInt:2.0F]; + [NSNumber numberWithInt:2.0l]; + [NSNumber numberWithInt:2.0L]; + @0x2f; + @04; + @0; + [NSNumber numberWithInt:0.0]; + [NSNumber numberWithInt:YES]; + [NSNumber numberWithInt:NO]; + [NSNumber numberWithInt:true]; + [NSNumber numberWithInt:false]; + @VAL_INT; + [NSNumber numberWithInt:VAL_UINT]; + + (void)[[NSNumber alloc] initWithInt:2]; + (void)[[NSNumber alloc] initWithInt:2U]; + + @+2; + @-2; + + [NSNumber numberWithUnsignedInt:'a']; + [NSNumber numberWithUnsignedInt:L'a']; + @2U; + @2U; + @2u; + @2U; + @2u; + @2U; + @2u; + @2u; + @2u; + @2u; + @2u; + [NSNumber numberWithUnsignedInt:2.0]; + [NSNumber numberWithUnsignedInt:2.0f]; + [NSNumber numberWithUnsignedInt:2.0F]; + [NSNumber numberWithUnsignedInt:2.0l]; + [NSNumber numberWithUnsignedInt:2.0L]; + @0x2fU; + @04U; + @0U; + [NSNumber numberWithUnsignedInt:0.0]; + [NSNumber numberWithUnsignedInt:YES]; + [NSNumber numberWithUnsignedInt:NO]; + [NSNumber numberWithUnsignedInt:true]; + [NSNumber numberWithUnsignedInt:false]; + [NSNumber numberWithUnsignedInt:VAL_INT]; + @VAL_UINT; + + [NSNumber numberWithLong:'a']; + [NSNumber numberWithLong:L'a']; + @2L; + @2L; + @2l; + @2L; + @2l; + @2L; + @2l; + @2l; + @2l; + @2l; + @2l; + [NSNumber numberWithLong:2.0]; + [NSNumber numberWithLong:2.0f]; + [NSNumber numberWithLong:2.0F]; + [NSNumber numberWithLong:2.0l]; + [NSNumber numberWithLong:2.0L]; + @0x2fL; + @04L; + @0L; + [NSNumber numberWithLong:0.0]; + [NSNumber numberWithLong:YES]; + [NSNumber numberWithLong:NO]; + [NSNumber numberWithLong:true]; + [NSNumber numberWithLong:false]; + [NSNumber numberWithLong:VAL_INT]; + [NSNumber numberWithLong:VAL_UINT]; + + [NSNumber numberWithUnsignedLong:'a']; + [NSNumber numberWithUnsignedLong:L'a']; + @2UL; + @2UL; + @2ul; + @2UL; + @2ul; + @2UL; + @2ul; + @2ul; + @2lu; + @2ul; + @2ul; + [NSNumber numberWithUnsignedLong:2.0]; + [NSNumber numberWithUnsignedLong:2.0f]; + [NSNumber numberWithUnsignedLong:2.0F]; + [NSNumber numberWithUnsignedLong:2.0l]; + [NSNumber numberWithUnsignedLong:2.0L]; + @0x2fUL; + @04UL; + @0UL; + [NSNumber numberWithUnsignedLong:0.0]; + [NSNumber numberWithUnsignedLong:YES]; + [NSNumber numberWithUnsignedLong:NO]; + [NSNumber numberWithUnsignedLong:true]; + [NSNumber numberWithUnsignedLong:false]; + [NSNumber numberWithUnsignedLong:VAL_INT]; + [NSNumber numberWithUnsignedLong:VAL_UINT]; + + [NSNumber numberWithLongLong:'a']; + [NSNumber numberWithLongLong:L'a']; + @2LL; + @2LL; + @2ll; + @2LL; + @2ll; + @2LL; + @2ll; + @2ll; + @2ll; + @2ll; + @2ll; + [NSNumber numberWithLongLong:2.0]; + [NSNumber numberWithLongLong:2.0f]; + [NSNumber numberWithLongLong:2.0F]; + [NSNumber numberWithLongLong:2.0l]; + [NSNumber numberWithLongLong:2.0L]; + @0x2fLL; + @04LL; + @0LL; + [NSNumber numberWithLongLong:0.0]; + [NSNumber numberWithLongLong:YES]; + [NSNumber numberWithLongLong:NO]; + [NSNumber numberWithLongLong:true]; + [NSNumber numberWithLongLong:false]; + [NSNumber numberWithLongLong:VAL_INT]; + [NSNumber numberWithLongLong:VAL_UINT]; + + [NSNumber numberWithUnsignedLongLong:'a']; + [NSNumber numberWithUnsignedLongLong:L'a']; + @2ULL; + @2ULL; + @2ull; + @2ULL; + @2ull; + @2ULL; + @2ull; + @2ull; + @2ull; + @2ull; + @2llu; + [NSNumber numberWithUnsignedLongLong:2.0]; + [NSNumber numberWithUnsignedLongLong:2.0f]; + [NSNumber numberWithUnsignedLongLong:2.0F]; + [NSNumber numberWithUnsignedLongLong:2.0l]; + [NSNumber numberWithUnsignedLongLong:2.0L]; + @0x2fULL; + @04ULL; + @0ULL; + [NSNumber numberWithUnsignedLongLong:0.0]; + [NSNumber numberWithUnsignedLongLong:YES]; + [NSNumber numberWithUnsignedLongLong:NO]; + [NSNumber numberWithUnsignedLongLong:true]; + [NSNumber numberWithUnsignedLongLong:false]; + [NSNumber numberWithUnsignedLongLong:VAL_INT]; + [NSNumber numberWithUnsignedLongLong:VAL_UINT]; + + [NSNumber numberWithFloat:'a']; + [NSNumber numberWithFloat:L'a']; + @2.0f; + @2.0f; + @2.0f; + @2.0f; + @2.0f; + @2.0f; + @2.0f; + @2.0f; + @2.0f; + @2.0f; + @2.0f; + @2.0f; + @2.0f; + @2.0F; + @2.0f; + @2.0f; + [NSNumber numberWithFloat:0x2f]; + [NSNumber numberWithFloat:04]; + @0.0f; + @0.0f; + [NSNumber numberWithFloat:YES]; + [NSNumber numberWithFloat:NO]; + [NSNumber numberWithFloat:true]; + [NSNumber numberWithFloat:false]; + [NSNumber numberWithFloat:VAL_INT]; + [NSNumber numberWithFloat:VAL_UINT]; + + [NSNumber numberWithDouble:'a']; + [NSNumber numberWithDouble:L'a']; + @2.0; + @2.0; + @2.0; + @2.0; + @2.0; + @2.0; + @2.0; + @2.0; + @2.0; + @2.0; + @2.0; + @2.0; + @2.0; + @2.0; + @2.0; + @2.0; + [NSNumber numberWithDouble:0x2f]; + [NSNumber numberWithDouble:04]; + @0.0; + @0.0; + [NSNumber numberWithDouble:YES]; + [NSNumber numberWithDouble:NO]; + [NSNumber numberWithDouble:true]; + [NSNumber numberWithDouble:false]; + [NSNumber numberWithDouble:VAL_INT]; + [NSNumber numberWithDouble:VAL_UINT]; + + [NSNumber numberWithBool:'a']; + [NSNumber numberWithBool:L'a']; + [NSNumber numberWithBool:2]; + [NSNumber numberWithBool:2U]; + [NSNumber numberWithBool:2u]; + [NSNumber numberWithBool:2L]; + [NSNumber numberWithBool:2l]; + [NSNumber numberWithBool:2LL]; + [NSNumber numberWithBool:2ll]; + [NSNumber numberWithBool:2ul]; + [NSNumber numberWithBool:2lu]; + [NSNumber numberWithBool:2ull]; + [NSNumber numberWithBool:2llu]; + [NSNumber numberWithBool:2.0]; + [NSNumber numberWithBool:2.0f]; + [NSNumber numberWithBool:2.0F]; + [NSNumber numberWithBool:2.0l]; + [NSNumber numberWithBool:2.0L]; + [NSNumber numberWithBool:0x2f]; + [NSNumber numberWithBool:04]; + [NSNumber numberWithBool:0]; + [NSNumber numberWithBool:0.0]; + @YES; + @NO; + @true; + @false; + [NSNumber numberWithBool:VAL_INT]; + [NSNumber numberWithBool:VAL_UINT]; + + [NSNumber numberWithInteger:'a']; + [NSNumber numberWithInteger:L'a']; + @2; + @2; + @2; + @2L; + @2l; + @2; + @2; + @2; + @2; + @2; + @2; + [NSNumber numberWithInteger:2.0]; + [NSNumber numberWithInteger:2.0f]; + [NSNumber numberWithInteger:2.0F]; + [NSNumber numberWithInteger:2.0l]; + [NSNumber numberWithInteger:2.0L]; + @0x2f; + @04; + @0; + [NSNumber numberWithInteger:0.0]; + [NSNumber numberWithInteger:YES]; + [NSNumber numberWithInteger:NO]; + [NSNumber numberWithInteger:true]; + [NSNumber numberWithInteger:false]; + [NSNumber numberWithInteger:VAL_INT]; + [NSNumber numberWithInteger:VAL_UINT]; + + [NSNumber numberWithUnsignedInteger:'a']; + [NSNumber numberWithUnsignedInteger:L'a']; + @2U; + @2U; + @2u; + @2U; + @2u; + @2U; + @2u; + @2ul; + @2lu; + @2u; + @2u; + [NSNumber numberWithUnsignedInteger:2.0]; + [NSNumber numberWithUnsignedInteger:2.0f]; + [NSNumber numberWithUnsignedInteger:2.0F]; + [NSNumber numberWithUnsignedInteger:2.0l]; + [NSNumber numberWithUnsignedInteger:2.0L]; + @0x2fU; + @04U; + @0U; + [NSNumber numberWithUnsignedInteger:0.0]; + [NSNumber numberWithUnsignedInteger:YES]; + [NSNumber numberWithUnsignedInteger:NO]; + [NSNumber numberWithUnsignedInteger:true]; + [NSNumber numberWithUnsignedInteger:false]; + [NSNumber numberWithUnsignedInteger:VAL_INT]; + [NSNumber numberWithUnsignedInteger:VAL_UINT]; +} diff --git a/clang/test/ARCMT/objcmt-subscripting-literals.m b/clang/test/ARCMT/objcmt-subscripting-literals.m new file mode 100644 index 00000000000..1632bf91ad1 --- /dev/null +++ b/clang/test/ARCMT/objcmt-subscripting-literals.m @@ -0,0 +1,137 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c +// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result + +typedef signed char BOOL; +#define nil ((void*) 0) + +@interface NSObject ++ (id)alloc; +@end + +@interface NSString : NSObject ++ (id)stringWithString:(NSString *)string; +- (id)initWithString:(NSString *)aString; +@end + +@interface NSArray : NSObject +- (id)objectAtIndex:(unsigned long)index; +- (id)objectAtIndexedSubscript:(int)index; +@end + +@interface NSArray (NSArrayCreation) ++ (id)array; ++ (id)arrayWithObject:(id)anObject; ++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt; ++ (id)arrayWithObjects:(id)firstObj, ...; ++ (id)arrayWithArray:(NSArray *)array; + +- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt; +- (id)initWithObjects:(id)firstObj, ...; +- (id)initWithArray:(NSArray *)array; + +- (id)objectAtIndex:(unsigned long)index; +@end + +@interface NSMutableArray : NSArray +- (void)replaceObjectAtIndex:(unsigned long)index withObject:(id)anObject; +- (void)setObject:(id)object atIndexedSubscript:(int)index; +@end + +@interface NSDictionary : NSObject +- (id)objectForKeyedSubscript:(id)key; +@end + +@interface NSDictionary (NSDictionaryCreation) ++ (id)dictionary; ++ (id)dictionaryWithObject:(id)object forKey:(id)key; ++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt; ++ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...; ++ (id)dictionaryWithDictionary:(NSDictionary *)dict; ++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys; + +- (id)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt; +- (id)initWithObjectsAndKeys:(id)firstObject, ...; +- (id)initWithDictionary:(NSDictionary *)otherDictionary; +- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys; + +- (id)objectForKey:(id)aKey; +@end + +@interface NSMutableDictionary : NSDictionary +- (void)setObject:(id)anObject forKey:(id)aKey; +- (void)setObject:(id)object forKeyedSubscript:(id)key; +@end + +@interface NSNumber : NSObject +@end + +@interface NSNumber (NSNumberCreation) ++ (NSNumber *)numberWithInt:(int)value; +@end + +#define M(x) (x) +#define PAIR(x) @#x, [NSNumber numberWithInt:(x)] +#define TWO(x) ((x), (x)) + +@interface I +@end +@implementation I +-(void) foo { + NSString *str; + NSArray *arr; + NSDictionary *dict; + + arr = [NSArray array]; + arr = [NSArray arrayWithObject:str]; + arr = [NSArray arrayWithObjects:str, str, nil]; + dict = [NSDictionary dictionary]; + dict = [NSDictionary dictionaryWithObject:arr forKey:str]; + dict = [NSDictionary dictionaryWithObjectsAndKeys: @"value1", @"key1", @"value2", @"key2", nil]; + dict = [NSDictionary dictionaryWithObjectsAndKeys: PAIR(1), PAIR(2), nil]; + dict = [NSDictionary dictionaryWithObjectsAndKeys: + @"value1", @"key1", +#ifdef BLAH + @"value2", @"key2", +#else + @"value3", @"key3", +#endif + nil ]; + + id o = [arr objectAtIndex:2]; + o = [dict objectForKey:@"key"]; + o = TWO([dict objectForKey:@"key"]); + o = [NSDictionary dictionaryWithObject:[NSDictionary dictionary] forKey:@"key"]; + NSMutableArray *marr = 0; + NSMutableDictionary *mdict = 0; + [marr replaceObjectAtIndex:2 withObject:@"val"]; + [mdict setObject:@"value" forKey:@"key"]; + [marr replaceObjectAtIndex:2 withObject:[arr objectAtIndex:4]]; + [mdict setObject:[dict objectForKey:@"key2"] forKey:@"key"]; + [mdict setObject:[dict objectForKey:@"key2"] forKey: +#if 1 + @"key1" +#else + @"key2" +#endif + ]; + [mdict setObject:[dict objectForKey: +#if 2 + @"key3" +#else + @"key4" +#endif + ] forKey:@"key"]; + [mdict setObject:@"value" forKey:[dict objectForKey: +#if 3 + @"key5" +#else + @"key6" +#endif + ] ]; + [mdict setObject:@"val" forKey:[dict objectForKey:@"key2"]]; + [mdict setObject:[dict objectForKey:@"key1"] forKey:[dict objectForKey:[NSArray arrayWithObject:@"arrkey"]]]; + __strong NSArray **parr = 0; + o = [*parr objectAtIndex:2]; +} +@end diff --git a/clang/test/ARCMT/objcmt-subscripting-literals.m.result b/clang/test/ARCMT/objcmt-subscripting-literals.m.result new file mode 100644 index 00000000000..cc93cb4906f --- /dev/null +++ b/clang/test/ARCMT/objcmt-subscripting-literals.m.result @@ -0,0 +1,137 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c +// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result + +typedef signed char BOOL; +#define nil ((void*) 0) + +@interface NSObject ++ (id)alloc; +@end + +@interface NSString : NSObject ++ (id)stringWithString:(NSString *)string; +- (id)initWithString:(NSString *)aString; +@end + +@interface NSArray : NSObject +- (id)objectAtIndex:(unsigned long)index; +- (id)objectAtIndexedSubscript:(int)index; +@end + +@interface NSArray (NSArrayCreation) ++ (id)array; ++ (id)arrayWithObject:(id)anObject; ++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt; ++ (id)arrayWithObjects:(id)firstObj, ...; ++ (id)arrayWithArray:(NSArray *)array; + +- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt; +- (id)initWithObjects:(id)firstObj, ...; +- (id)initWithArray:(NSArray *)array; + +- (id)objectAtIndex:(unsigned long)index; +@end + +@interface NSMutableArray : NSArray +- (void)replaceObjectAtIndex:(unsigned long)index withObject:(id)anObject; +- (void)setObject:(id)object atIndexedSubscript:(int)index; +@end + +@interface NSDictionary : NSObject +- (id)objectForKeyedSubscript:(id)key; +@end + +@interface NSDictionary (NSDictionaryCreation) ++ (id)dictionary; ++ (id)dictionaryWithObject:(id)object forKey:(id)key; ++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt; ++ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...; ++ (id)dictionaryWithDictionary:(NSDictionary *)dict; ++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys; + +- (id)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt; +- (id)initWithObjectsAndKeys:(id)firstObject, ...; +- (id)initWithDictionary:(NSDictionary *)otherDictionary; +- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys; + +- (id)objectForKey:(id)aKey; +@end + +@interface NSMutableDictionary : NSDictionary +- (void)setObject:(id)anObject forKey:(id)aKey; +- (void)setObject:(id)object forKeyedSubscript:(id)key; +@end + +@interface NSNumber : NSObject +@end + +@interface NSNumber (NSNumberCreation) ++ (NSNumber *)numberWithInt:(int)value; +@end + +#define M(x) (x) +#define PAIR(x) @#x, [NSNumber numberWithInt:(x)] +#define TWO(x) ((x), (x)) + +@interface I +@end +@implementation I +-(void) foo { + NSString *str; + NSArray *arr; + NSDictionary *dict; + + arr = @[]; + arr = @[str]; + arr = @[str, str]; + dict = @{}; + dict = @{str: arr}; + dict = @{@"key1": @"value1", @"key2": @"value2"}; + dict = [NSDictionary dictionaryWithObjectsAndKeys: PAIR(1), PAIR(2), nil]; + dict = [NSDictionary dictionaryWithObjectsAndKeys: + @"value1", @"key1", +#ifdef BLAH + @"value2", @"key2", +#else + @"value3", @"key3", +#endif + nil ]; + + id o = arr[2]; + o = dict[@"key"]; + o = TWO(dict[@"key"]); + o = @{@"key": @{}}; + NSMutableArray *marr = 0; + NSMutableDictionary *mdict = 0; + marr[2] = @"val"; + mdict[@"key"] = @"value"; + marr[2] = arr[4]; + mdict[@"key"] = dict[@"key2"]; + [mdict setObject:dict[@"key2"] forKey: +#if 1 + @"key1" +#else + @"key2" +#endif + ]; + mdict[@"key"] = [dict objectForKey: +#if 2 + @"key3" +#else + @"key4" +#endif + ]; + mdict[[dict objectForKey: +#if 3 + @"key5" +#else + @"key6" +#endif + ]] = @"value"; + mdict[dict[@"key2"]] = @"val"; + mdict[dict[@[@"arrkey"]]] = dict[@"key1"]; + __strong NSArray **parr = 0; + o = (*parr)[2]; +} +@end diff --git a/clang/test/ARCMT/with-arc-mode-migrate.m b/clang/test/ARCMT/with-arc-mode-migrate.m index 32bcad19504..468859478eb 100644 --- a/clang/test/ARCMT/with-arc-mode-migrate.m +++ b/clang/test/ARCMT/with-arc-mode-migrate.m @@ -1,7 +1,7 @@ // RUN: rm -rf %t // RUN: %clang_cc1 -fsyntax-only -fobjc-arc -x objective-c %s.result -// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -fsyntax-only -fobjc-arc %s -// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result +// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t -fsyntax-only -fobjc-arc %s +// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result // RUN: rm -rf %t @protocol NSObject diff --git a/clang/test/ARCMT/with-arc-mode-migrate.m.result b/clang/test/ARCMT/with-arc-mode-migrate.m.result index f060793f6eb..dd34b999087 100644 --- a/clang/test/ARCMT/with-arc-mode-migrate.m.result +++ b/clang/test/ARCMT/with-arc-mode-migrate.m.result @@ -1,7 +1,7 @@ // RUN: rm -rf %t // RUN: %clang_cc1 -fsyntax-only -fobjc-arc -x objective-c %s.result -// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -fsyntax-only -fobjc-arc %s -// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result +// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t -fsyntax-only -fobjc-arc %s +// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result // RUN: rm -rf %t @protocol NSObject diff --git a/clang/tools/arcmt-test/CMakeLists.txt b/clang/tools/arcmt-test/CMakeLists.txt index 9227f8ee63c..a0029b416f2 100644 --- a/clang/tools/arcmt-test/CMakeLists.txt +++ b/clang/tools/arcmt-test/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_USED_LIBS clangARCMigrate + clangEdit clangRewrite ) diff --git a/clang/tools/arcmt-test/Makefile b/clang/tools/arcmt-test/Makefile index c143e27f33e..f5ca81a6d11 100644 --- a/clang/tools/arcmt-test/Makefile +++ b/clang/tools/arcmt-test/Makefile @@ -19,6 +19,6 @@ NO_INSTALL = 1 LINK_COMPONENTS := support mc USEDLIBS = clangIndex.a clangARCMigrate.a clangRewrite.a \ clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \ - clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a + clangSema.a clangEdit.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/Makefile diff --git a/clang/tools/arcmt-test/arcmt-test.cpp b/clang/tools/arcmt-test/arcmt-test.cpp index 881a058c2c4..2dc8034e329 100644 --- a/clang/tools/arcmt-test/arcmt-test.cpp +++ b/clang/tools/arcmt-test/arcmt-test.cpp @@ -135,9 +135,8 @@ static bool checkForMigration(StringRef resourcesPath, } static void printResult(FileRemapper &remapper, raw_ostream &OS) { - CompilerInvocation CI; - remapper.applyMappings(CI); - PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); + PreprocessorOptions PPOpts; + remapper.applyMappings(PPOpts); // The changed files will be in memory buffers, print them. for (unsigned i = 0, e = PPOpts.RemappedFileBuffers.size(); i != e; ++i) { const llvm::MemoryBuffer *mem = PPOpts.RemappedFileBuffers[i].second; diff --git a/clang/tools/c-arcmt-test/c-arcmt-test.c b/clang/tools/c-arcmt-test/c-arcmt-test.c index 5522b33e23a..b91d3e1b986 100644 --- a/clang/tools/c-arcmt-test/c-arcmt-test.c +++ b/clang/tools/c-arcmt-test/c-arcmt-test.c @@ -34,22 +34,51 @@ static int print_remappings(const char *path) { return 0; } +static int print_remappings_filelist(const char **files, unsigned numFiles) { + CXRemapping remap; + unsigned i, N; + CXString origFname; + CXString transFname; + + remap = clang_getRemappingsFromFileList(files, numFiles); + if (!remap) + return 1; + + N = clang_remap_getNumFiles(remap); + for (i = 0; i != N; ++i) { + clang_remap_getFilenames(remap, i, &origFname, &transFname); + + fprintf(stdout, "%s\n", clang_getCString(origFname)); + fprintf(stdout, "%s\n", clang_getCString(transFname)); + + clang_disposeString(origFname); + clang_disposeString(transFname); + } + + clang_remap_dispose(remap); + return 0; +} + /******************************************************************************/ /* Command line processing. */ /******************************************************************************/ static void print_usage(void) { fprintf(stderr, - "usage: c-arcmt-test -arcmt-migrate-directory <path>\n\n\n"); + "usage: c-arcmt-test -mt-migrate-directory <path>\n" + " c-arcmt-test <remap-file-path1> <remap-file-path2> ...\n\n\n"); } /***/ int carcmttest_main(int argc, const char **argv) { clang_enableStackTraces(); - if (argc == 3 && strncmp(argv[1], "-arcmt-migrate-directory", 24) == 0) + if (argc == 3 && strncmp(argv[1], "-mt-migrate-directory", 21) == 0) return print_remappings(argv[2]); + if (argc > 1) + return print_remappings_filelist(argv+1, argc-1); + print_usage(); return 1; } diff --git a/clang/tools/driver/CMakeLists.txt b/clang/tools/driver/CMakeLists.txt index 539ae800587..c4c864bdbf5 100644 --- a/clang/tools/driver/CMakeLists.txt +++ b/clang/tools/driver/CMakeLists.txt @@ -5,10 +5,12 @@ set( LLVM_USED_LIBS clangBasic clangCodeGen clangDriver + clangEdit clangFrontend clangIndex clangLex clangParse + clangEdit clangARCMigrate clangRewrite clangSema diff --git a/clang/tools/driver/Makefile b/clang/tools/driver/Makefile index c7d91a728d2..d828f678683 100644 --- a/clang/tools/driver/Makefile +++ b/clang/tools/driver/Makefile @@ -36,7 +36,7 @@ USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \ clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \ clangStaticAnalyzerCore.a \ clangAnalysis.a clangIndex.a clangARCMigrate.a clangRewrite.a \ - clangAST.a clangLex.a clangBasic.a + clangEdit.a clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/Makefile diff --git a/clang/tools/libclang/ARCMigrate.cpp b/clang/tools/libclang/ARCMigrate.cpp index 58f8ba454db..5ee5cf6e4ef 100644 --- a/clang/tools/libclang/ARCMigrate.cpp +++ b/clang/tools/libclang/ARCMigrate.cpp @@ -74,6 +74,47 @@ CXRemapping clang_getRemappings(const char *migrate_dir_path) { return remap.take(); } +CXRemapping clang_getRemappingsFromFileList(const char **filePaths, + unsigned numFiles) { + bool Logging = ::getenv("LIBCLANG_LOGGING"); + + OwningPtr<Remap> remap(new Remap()); + + if (numFiles == 0) { + if (Logging) + llvm::errs() << "clang_getRemappingsFromFileList was called with " + "numFiles=0\n"; + return remap.take(); + } + + if (!filePaths) { + if (Logging) + llvm::errs() << "clang_getRemappingsFromFileList was called with " + "NULL filePaths\n"; + return 0; + } + + TextDiagnosticBuffer diagBuffer; + SmallVector<StringRef, 32> Files; + for (unsigned i = 0; i != numFiles; ++i) + Files.push_back(filePaths[i]); + + bool err = arcmt::getFileRemappingsFromFileList(remap->Vec, Files, + &diagBuffer); + + if (err) { + if (Logging) { + llvm::errs() << "Error by clang_getRemappingsFromFileList\n"; + for (TextDiagnosticBuffer::const_iterator + I = diagBuffer.err_begin(), E = diagBuffer.err_end(); I != E; ++I) + llvm::errs() << I->second << '\n'; + } + return remap.take(); + } + + return remap.take(); +} + unsigned clang_remap_getNumFiles(CXRemapping map) { return static_cast<Remap *>(map)->Vec.size(); diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt index 742448d2ea0..66a1710bac1 100644 --- a/clang/tools/libclang/CMakeLists.txt +++ b/clang/tools/libclang/CMakeLists.txt @@ -6,6 +6,7 @@ set(LLVM_USED_LIBS clangSerialization clangIndex clangSema + clangEdit clangAST clangLex clangBasic) diff --git a/clang/tools/libclang/Makefile b/clang/tools/libclang/Makefile index 375f7f20fe0..1fff166bbf8 100644 --- a/clang/tools/libclang/Makefile +++ b/clang/tools/libclang/Makefile @@ -18,7 +18,8 @@ SHARED_LIBRARY = 1 LINK_COMPONENTS := support mc USEDLIBS = clangARCMigrate.a clangRewrite.a clangFrontend.a clangDriver.a \ clangSerialization.a \ - clangParse.a clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a + clangParse.a clangSema.a clangEdit.a clangAnalysis.a \ + clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/Makefile diff --git a/clang/tools/libclang/libclang.exports b/clang/tools/libclang/libclang.exports index 8645b15f7b2..1900ac86c05 100644 --- a/clang/tools/libclang/libclang.exports +++ b/clang/tools/libclang/libclang.exports @@ -132,6 +132,7 @@ clang_getRange clang_getRangeEnd clang_getRangeStart clang_getRemappings +clang_getRemappingsFromFileList clang_getResultType clang_getSpecializedCursorTemplate clang_getSpellingLocation diff --git a/clang/unittests/Frontend/Makefile b/clang/unittests/Frontend/Makefile index 7ec2b894a04..7c282d6b47f 100644 --- a/clang/unittests/Frontend/Makefile +++ b/clang/unittests/Frontend/Makefile @@ -13,7 +13,7 @@ LINK_COMPONENTS := support mc USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \ clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \ clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \ - clangIndex.a clangARCMigrate.a clangRewrite.a \ + clangIndex.a clangARCMigrate.a clangRewrite.a clangEdit.a \ clangAnalysis.a clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/unittests/Makefile diff --git a/clang/unittests/Lex/LexerTest.cpp b/clang/unittests/Lex/LexerTest.cpp index 584ca10365d..56581fcc638 100644 --- a/clang/unittests/Lex/LexerTest.cpp +++ b/clang/unittests/Lex/LexerTest.cpp @@ -66,10 +66,10 @@ TEST_F(LexerTest, LexAPI) { "N(INN(val)) N(NOF1) N(NOF2) N(val)"; MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source); - SourceMgr.createMainFileIDForMemBuffer(buf); + FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf); VoidModuleLoader ModLoader; - HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target); + HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, Target.getPtr()); Preprocessor PP(Diags, LangOpts, Target.getPtr(), SourceMgr, HeaderInfo, ModLoader, |