//===--- OptionalTryMigratorPass.cpp -------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/AST/ASTVisitor.h" #include "swift/AST/Expr.h" #include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Types.h" #include "swift/IDE/SourceEntityWalker.h" #include "swift/Migrator/ASTMigratorPass.h" #include "swift/Parse/Lexer.h" using namespace swift; using namespace swift::migrator; namespace { class OptionalTryMigratorPass: public ASTMigratorPass, public SourceEntityWalker { bool explicitCastActiveForOptionalTry = false; bool walkToExprPre(Expr *E) override { if (dyn_cast(E) || E->isImplicit()) { // Look through parentheses and implicit expressions. return true; } if (const auto *explicitCastExpr = dyn_cast(E)) { // If the user has already provided an explicit cast for the // 'try?', then we don't need to add one. So let's track whether // one is active explicitCastActiveForOptionalTry = true; } else if (const auto *optTryExpr = dyn_cast(E)) { wrapTryInCastIfNeeded(optTryExpr); return false; } else if (explicitCastActiveForOptionalTry) { // If an explicit cast is active and we are entering a new // expression that is not an OptionalTryExpr, then the cast // does not apply to the OptionalTryExpr. explicitCastActiveForOptionalTry = false; } return true; } bool walkToExprPost(Expr *E) override { explicitCastActiveForOptionalTry = false; return true; } void wrapTryInCastIfNeeded(const OptionalTryExpr *optTryExpr) { if (explicitCastActiveForOptionalTry) { // There's already an explicit cast here; we don't need to add anything return; } if (!optTryExpr->getSubExpr()->getType()->getOptionalObjectType()) { // This 'try?' doesn't wrap an optional, so its behavior does not // change from Swift 4 to Swift 5 return; } Type typeToPreserve = optTryExpr->getType(); auto typeName = typeToPreserve->getStringAsComponent(); auto range = optTryExpr->getSourceRange(); auto charRange = Lexer::getCharSourceRangeFromSourceRange(SM, range); Editor.insertWrap("((", charRange, (Twine(") as ") + typeName + ")").str()); } public: OptionalTryMigratorPass(EditorAdapter &Editor, SourceFile *SF, const MigratorOptions &Opts) : ASTMigratorPass(Editor, SF, Opts) {} }; } // end anonymous namespace void migrator::runOptionalTryMigratorPass(EditorAdapter &Editor, SourceFile *SF, const MigratorOptions &Opts) { OptionalTryMigratorPass { Editor, SF, Opts }.walk(SF); }