diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Edit')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Edit/Commit.cpp | 6 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp | 80 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp | 180 |
3 files changed, 243 insertions, 23 deletions
diff --git a/contrib/llvm/tools/clang/lib/Edit/Commit.cpp b/contrib/llvm/tools/clang/lib/Edit/Commit.cpp index 41c72e4..0b4ea3e 100644 --- a/contrib/llvm/tools/clang/lib/Edit/Commit.cpp +++ b/contrib/llvm/tools/clang/lib/Edit/Commit.cpp @@ -8,10 +8,10 @@ //===----------------------------------------------------------------------===// #include "clang/Edit/Commit.h" +#include "clang/Basic/SourceManager.h" #include "clang/Edit/EditedSource.h" #include "clang/Lex/Lexer.h" -#include "clang/Lex/PreprocessingRecord.h" -#include "clang/Basic/SourceManager.h" +#include "clang/Lex/PPConditionalDirectiveRecord.h" using namespace clang; using namespace edit; @@ -37,7 +37,7 @@ CharSourceRange Commit::Edit::getInsertFromRange(SourceManager &SM) const { Commit::Commit(EditedSource &Editor) : SourceMgr(Editor.getSourceManager()), LangOpts(Editor.getLangOpts()), - PPRec(Editor.getPreprocessingRecord()), + PPRec(Editor.getPPCondDirectiveRecord()), Editor(&Editor), IsCommitable(true) { } bool Commit::insert(SourceLocation loc, StringRef text, diff --git a/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp b/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp index b2a1663..dd99ca9 100644 --- a/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp +++ b/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp @@ -8,10 +8,11 @@ //===----------------------------------------------------------------------===// #include "clang/Edit/EditedSource.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/SourceManager.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" @@ -23,7 +24,7 @@ void EditsReceiver::remove(CharSourceRange range) { } StringRef EditedSource::copyString(const Twine &twine) { - llvm::SmallString<128> Data; + SmallString<128> Data; return copyString(twine.toStringRef(Data)); } @@ -88,7 +89,7 @@ bool EditedSource::commitInsertFromRange(SourceLocation OrigLoc, if (Len == 0) return true; - llvm::SmallString<128> StrVec; + SmallString<128> StrVec; FileOffset BeginOffs = InsertFromRangeOffs; FileOffset EndOffs = BeginOffs.getWithOffset(Len); FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs); @@ -239,13 +240,78 @@ bool EditedSource::commit(const Commit &commit) { return true; } +// \brief Returns true if it is ok to make the two given characters adjacent. +static bool canBeJoined(char left, char right, const LangOptions &LangOpts) { + // FIXME: Should use TokenConcatenation to make sure we don't allow stuff like + // making two '<' adjacent. + return !(Lexer::isIdentifierBodyChar(left, LangOpts) && + Lexer::isIdentifierBodyChar(right, LangOpts)); +} + +/// \brief Returns true if it is ok to eliminate the trailing whitespace between +/// the given characters. +static bool canRemoveWhitespace(char left, char beforeWSpace, char right, + const LangOptions &LangOpts) { + if (!canBeJoined(left, right, LangOpts)) + return false; + if (isWhitespace(left) || isWhitespace(right)) + return true; + if (canBeJoined(beforeWSpace, right, LangOpts)) + return false; // the whitespace was intentional, keep it. + return true; +} + +/// \brief Check the range that we are going to remove and: +/// -Remove any trailing whitespace if possible. +/// -Insert a space if removing the range is going to mess up the source tokens. +static void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts, + SourceLocation Loc, FileOffset offs, + unsigned &len, StringRef &text) { + assert(len && text.empty()); + SourceLocation BeginTokLoc = Lexer::GetBeginningOfToken(Loc, SM, LangOpts); + if (BeginTokLoc != Loc) + return; // the range is not at the beginning of a token, keep the range. + + bool Invalid = false; + StringRef buffer = SM.getBufferData(offs.getFID(), &Invalid); + if (Invalid) + return; + + unsigned begin = offs.getOffset(); + unsigned end = begin + len; + + // FIXME: Remove newline. + + if (begin == 0) { + if (buffer[end] == ' ') + ++len; + return; + } + + if (buffer[end] == ' ') { + if (canRemoveWhitespace(/*left=*/buffer[begin-1], + /*beforeWSpace=*/buffer[end-1], + /*right=*/buffer[end+1], + LangOpts)) + ++len; + return; + } + + if (!canBeJoined(buffer[begin-1], buffer[end], LangOpts)) + text = " "; +} + static void applyRewrite(EditsReceiver &receiver, StringRef text, FileOffset offs, unsigned len, - const SourceManager &SM) { + const SourceManager &SM, const LangOptions &LangOpts) { assert(!offs.getFID().isInvalid()); SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID()); Loc = Loc.getLocWithOffset(offs.getOffset()); assert(Loc.isFileID()); + + if (text.empty()) + adjustRemoval(SM, LangOpts, Loc, offs, len, text); + CharSourceRange range = CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(len)); @@ -262,7 +328,7 @@ static void applyRewrite(EditsReceiver &receiver, } void EditedSource::applyRewrites(EditsReceiver &receiver) { - llvm::SmallString<128> StrVec; + SmallString<128> StrVec; FileOffset CurOffs, CurEnd; unsigned CurLen; @@ -288,14 +354,14 @@ void EditedSource::applyRewrites(EditsReceiver &receiver) { continue; } - applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr); + applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr, LangOpts); CurOffs = offs; StrVec = act.Text; CurLen = act.RemoveLen; CurEnd = CurOffs.getWithOffset(CurLen); } - applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr); + applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr, LangOpts); } void EditedSource::clearRewrites() { diff --git a/contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp index de96fee..f4206fb 100644 --- a/contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp +++ b/contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -12,12 +12,13 @@ //===----------------------------------------------------------------------===// #include "clang/Edit/Rewriters.h" -#include "clang/Edit/Commit.h" -#include "clang/Lex/Lexer.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/ExprObjC.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" #include "clang/AST/NSAPI.h" +#include "clang/AST/ParentMap.h" +#include "clang/Edit/Commit.h" +#include "clang/Lex/Lexer.h" using namespace clang; using namespace edit; @@ -295,9 +296,8 @@ bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg, if (!Method) return false; - const ObjCInterfaceDecl * - IFace = NS.getASTContext().getObjContainingInterface( - const_cast<ObjCMethodDecl *>(Method)); + const ObjCInterfaceDecl *IFace = + NS.getASTContext().getObjContainingInterface(Method); if (!IFace) return false; Selector Sel = Msg->getSelector(); @@ -325,7 +325,8 @@ bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg, //===----------------------------------------------------------------------===// static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg, - const NSAPI &NS, Commit &commit); + const NSAPI &NS, Commit &commit, + const ParentMap *PMap); static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit); static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg, @@ -336,13 +337,14 @@ static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit); bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, - const NSAPI &NS, Commit &commit) { + const NSAPI &NS, Commit &commit, + const ParentMap *PMap) { IdentifierInfo *II = 0; if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts())) return false; if (II == NS.getNSClassId(NSAPI::ClassId_NSArray)) - return rewriteToArrayLiteral(Msg, NS, commit); + return rewriteToArrayLiteral(Msg, NS, commit, PMap); if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary)) return rewriteToDictionaryLiteral(Msg, NS, commit); if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber)) @@ -353,6 +355,19 @@ bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, return false; } +/// \brief Returns true if the immediate message arguments of \c Msg should not +/// be rewritten because it will interfere with the rewrite of the parent +/// message expression. e.g. +/// \code +/// [NSDictionary dictionaryWithObjects: +/// [NSArray arrayWithObjects:@"1", @"2", nil] +/// forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]]; +/// \endcode +/// It will return true for this because we are going to rewrite this directly +/// to a dictionary literal without any array literals. +static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg, + const NSAPI &NS); + //===----------------------------------------------------------------------===// // rewriteToArrayLiteral. //===----------------------------------------------------------------------===// @@ -361,7 +376,15 @@ bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, static void objectifyExpr(const Expr *E, Commit &commit); static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg, - const NSAPI &NS, Commit &commit) { + const NSAPI &NS, Commit &commit, + const ParentMap *PMap) { + if (PMap) { + const ObjCMessageExpr *ParentMsg = + dyn_cast_or_null<ObjCMessageExpr>(PMap->getParentIgnoreParenCasts(Msg)); + if (shouldNotRewriteImmediateMessageArgs(ParentMsg, NS)) + return false; + } + Selector Sel = Msg->getSelector(); SourceRange MsgRange = Msg->getSourceRange(); @@ -411,6 +434,59 @@ static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg, // rewriteToDictionaryLiteral. //===----------------------------------------------------------------------===// +/// \brief If \c Msg is an NSArray creation message or literal, this gets the +/// objects that were used to create it. +/// \returns true if it is an NSArray and we got objects, or false otherwise. +static bool getNSArrayObjects(const Expr *E, const NSAPI &NS, + SmallVectorImpl<const Expr *> &Objs) { + if (!E) + return false; + + E = E->IgnoreParenCasts(); + if (!E) + return false; + + if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) { + IdentifierInfo *Cls = 0; + if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts())) + return false; + + if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray)) + return false; + + Selector Sel = Msg->getSelector(); + if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) + return true; // empty array. + + if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) { + if (Msg->getNumArgs() != 1) + return false; + Objs.push_back(Msg->getArg(0)); + return true; + } + + if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) || + Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) { + if (Msg->getNumArgs() == 0) + return false; + const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1); + if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr)) + return false; + + for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i) + Objs.push_back(Msg->getArg(i)); + return true; + } + + } else if (const ObjCArrayLiteral *ArrLit = dyn_cast<ObjCArrayLiteral>(E)) { + for (unsigned i = 0, e = ArrLit->getNumElements(); i != e; ++i) + Objs.push_back(ArrLit->getElement(i)); + return true; + } + + return false; +} + static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit) { Selector Sel = Msg->getSelector(); @@ -481,6 +557,83 @@ static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg, return true; } + if (Sel == NS.getNSDictionarySelector( + NSAPI::NSDict_dictionaryWithObjectsForKeys) || + Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) { + if (Msg->getNumArgs() != 2) + return false; + + SmallVector<const Expr *, 8> Vals; + if (!getNSArrayObjects(Msg->getArg(0), NS, Vals)) + return false; + + SmallVector<const Expr *, 8> Keys; + if (!getNSArrayObjects(Msg->getArg(1), NS, Keys)) + return false; + + if (Vals.size() != Keys.size()) + return false; + + if (Vals.empty()) { + commit.replace(MsgRange, "@{}"); + return true; + } + + for (unsigned i = 0, n = Vals.size(); i < n; ++i) { + objectifyExpr(Vals[i], commit); + objectifyExpr(Keys[i], commit); + + SourceRange ValRange = Vals[i]->getSourceRange(); + SourceRange KeyRange = Keys[i]->getSourceRange(); + // Insert value after key. + commit.insertAfterToken(KeyRange.getEnd(), ": "); + commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true); + } + // Range of arguments up until and including the last key. + // The first value is cut off, the value will move after the key. + SourceRange ArgRange(Keys.front()->getLocStart(), + Keys.back()->getLocEnd()); + commit.insertWrap("@{", ArgRange, "}"); + commit.replaceWithInner(MsgRange, ArgRange); + return true; + } + + return false; +} + +static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg, + const NSAPI &NS) { + if (!Msg) + return false; + + IdentifierInfo *II = 0; + if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts())) + return false; + + if (II != NS.getNSClassId(NSAPI::ClassId_NSDictionary)) + return false; + + Selector Sel = Msg->getSelector(); + if (Sel == NS.getNSDictionarySelector( + NSAPI::NSDict_dictionaryWithObjectsForKeys) || + Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) { + if (Msg->getNumArgs() != 2) + return false; + + SmallVector<const Expr *, 8> Vals; + if (!getNSArrayObjects(Msg->getArg(0), NS, Vals)) + return false; + + SmallVector<const Expr *, 8> Keys; + if (!getNSArrayObjects(Msg->getArg(1), NS, Keys)) + return false; + + if (Vals.size() != Keys.size()) + return false; + + return true; + } + return false; } @@ -540,7 +693,7 @@ static bool getLiteralInfo(SourceRange literalRange, if (text.empty()) return false; - llvm::Optional<bool> UpperU, UpperL; + Optional<bool> UpperU, UpperL; bool UpperF = false; struct Suff { @@ -624,7 +777,7 @@ static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg, ASTContext &Ctx = NS.getASTContext(); Selector Sel = Msg->getSelector(); - llvm::Optional<NSAPI::NSNumberLiteralMethodKind> + Optional<NSAPI::NSNumberLiteralMethodKind> MKOpt = NS.getNSNumberLiteralMethodKind(Sel); if (!MKOpt) return false; @@ -828,7 +981,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, ASTContext &Ctx = NS.getASTContext(); Selector Sel = Msg->getSelector(); - llvm::Optional<NSAPI::NSNumberLiteralMethodKind> + Optional<NSAPI::NSNumberLiteralMethodKind> MKOpt = NS.getNSNumberLiteralMethodKind(Sel); if (!MKOpt) return false; @@ -921,6 +1074,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, case CK_NonAtomicToAtomic: case CK_CopyAndAutoreleaseBlockObject: case CK_BuiltinFnToFnPtr: + case CK_ZeroToOCLEvent: return false; } } |