diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2013-01-04 18:30:08 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2013-01-04 18:30:08 +0000 |
commit | 03fbe3ef81e75bcbc8a54a301bd617faee93b40b (patch) | |
tree | b69132332cd0083b5c78de395ceacf16c856b122 /clang/lib/ARCMigrate/TransProtectedScope.cpp | |
parent | aa1ce901ebfbc1bfa58705f2660a8693f9c21296 (diff) | |
download | bcm5719-llvm-03fbe3ef81e75bcbc8a54a301bd617faee93b40b.tar.gz bcm5719-llvm-03fbe3ef81e75bcbc8a54a301bd617faee93b40b.zip |
[arcmt] Adds brackets in case statements that "contain" initialization of retaining
variable, thus emitting the "switch case is in protected scope" error.
rdar://12952016
llvm-svn: 171484
Diffstat (limited to 'clang/lib/ARCMigrate/TransProtectedScope.cpp')
-rw-r--r-- | clang/lib/ARCMigrate/TransProtectedScope.cpp | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/clang/lib/ARCMigrate/TransProtectedScope.cpp b/clang/lib/ARCMigrate/TransProtectedScope.cpp new file mode 100644 index 00000000000..b2026006256 --- /dev/null +++ b/clang/lib/ARCMigrate/TransProtectedScope.cpp @@ -0,0 +1,118 @@ +//===--- 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<CaseCollector> { + llvm::SmallVectorImpl<CaseInfo> &Cases; + +public: + CaseCollector(llvm::SmallVectorImpl<CaseInfo> &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<CaseInfo> &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<CaseInfo> &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<CaseInfo, 16> 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; + } +} |