forked from OSchip/llvm-project
119 lines
3.7 KiB
C++
119 lines
3.7 KiB
C++
//===--- 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;
|
|
}
|
|
}
|