//===--- TransProtectedScope.cpp - Transformations to ARC mode ------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Adds brackets in case statements that "contain" initialization of retaining // variable, thus emitting the "switch case is in protected scope" error. // //===----------------------------------------------------------------------===// #include "Transforms.h" #include "Internals.h" #include "clang/Sema/SemaDiagnostic.h" using namespace clang; using namespace arcmt; using namespace trans; namespace { struct CaseInfo { SwitchCase *SC; SourceRange Range; bool FixedBypass; CaseInfo() : SC(0), FixedBypass(false) {} CaseInfo(SwitchCase *S, SourceRange Range) : SC(S), Range(Range), FixedBypass(false) {} }; class CaseCollector : public RecursiveASTVisitor { llvm::SmallVectorImpl &Cases; public: CaseCollector(llvm::SmallVectorImpl &Cases) : Cases(Cases) { } bool VisitSwitchStmt(SwitchStmt *S) { SourceLocation NextLoc = S->getLocEnd(); SwitchCase *Curr = S->getSwitchCaseList(); // We iterate over case statements in reverse source-order. while (Curr) { Cases.push_back(CaseInfo(Curr,SourceRange(Curr->getLocStart(), NextLoc))); NextLoc = Curr->getLocStart(); Curr = Curr->getNextSwitchCase(); } return true; } }; } // anonymous namespace static bool isInRange(FullSourceLoc Loc, SourceRange R) { return !Loc.isBeforeInTranslationUnitThan(R.getBegin()) && Loc.isBeforeInTranslationUnitThan(R.getEnd()); } static bool handleProtectedNote(const StoredDiagnostic &Diag, llvm::SmallVectorImpl &Cases, TransformActions &TA) { assert(Diag.getLevel() == DiagnosticsEngine::Note); for (unsigned i = 0; i != Cases.size(); i++) { CaseInfo &info = Cases[i]; if (isInRange(Diag.getLocation(), info.Range)) { TA.clearDiagnostic(Diag.getID(), Diag.getLocation()); if (!info.FixedBypass) { TA.insertAfterToken(info.SC->getColonLoc(), " {"); TA.insert(info.Range.getEnd(), "}\n"); info.FixedBypass = true; } return true; } } return false; } static void handleProtectedScopeError(CapturedDiagList::iterator &DiagI, CapturedDiagList::iterator DiagE, llvm::SmallVectorImpl &Cases, TransformActions &TA) { Transaction Trans(TA); assert(DiagI->getID() == diag::err_switch_into_protected_scope); SourceLocation ErrLoc = DiagI->getLocation(); bool handledAllNotes = true; ++DiagI; for (; DiagI != DiagE && DiagI->getLevel() == DiagnosticsEngine::Note; ++DiagI) { if (!handleProtectedNote(*DiagI, Cases, TA)) handledAllNotes = false; } if (handledAllNotes) TA.clearDiagnostic(diag::err_switch_into_protected_scope, ErrLoc); } void ProtectedScopeTraverser::traverseBody(BodyContext &BodyCtx) { MigrationPass &Pass = BodyCtx.getMigrationContext().Pass; SmallVector Cases; CaseCollector(Cases).TraverseStmt(BodyCtx.getTopStmt()); SourceRange BodyRange = BodyCtx.getTopStmt()->getSourceRange(); const CapturedDiagList &DiagList = Pass.getDiags(); CapturedDiagList::iterator I = DiagList.begin(), E = DiagList.end(); while (I != E) { if (I->getID() == diag::err_switch_into_protected_scope && isInRange(I->getLocation(), BodyRange)) { handleProtectedScopeError(I, E, Cases, Pass.TA); continue; } ++I; } }