clang API Documentation
00001 //===--- TransProtectedScope.cpp - Transformations to ARC mode ------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // Adds brackets in case statements that "contain" initialization of retaining 00011 // variable, thus emitting the "switch case is in protected scope" error. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "Transforms.h" 00016 #include "Internals.h" 00017 #include "clang/AST/ASTContext.h" 00018 #include "clang/Sema/SemaDiagnostic.h" 00019 00020 using namespace clang; 00021 using namespace arcmt; 00022 using namespace trans; 00023 00024 namespace { 00025 00026 class LocalRefsCollector : public RecursiveASTVisitor<LocalRefsCollector> { 00027 SmallVectorImpl<DeclRefExpr *> &Refs; 00028 00029 public: 00030 LocalRefsCollector(SmallVectorImpl<DeclRefExpr *> &refs) 00031 : Refs(refs) { } 00032 00033 bool VisitDeclRefExpr(DeclRefExpr *E) { 00034 if (ValueDecl *D = E->getDecl()) 00035 if (D->getDeclContext()->getRedeclContext()->isFunctionOrMethod()) 00036 Refs.push_back(E); 00037 return true; 00038 } 00039 }; 00040 00041 struct CaseInfo { 00042 SwitchCase *SC; 00043 SourceRange Range; 00044 enum { 00045 St_Unchecked, 00046 St_CannotFix, 00047 St_Fixed 00048 } State; 00049 00050 CaseInfo() : SC(nullptr), State(St_Unchecked) {} 00051 CaseInfo(SwitchCase *S, SourceRange Range) 00052 : SC(S), Range(Range), State(St_Unchecked) {} 00053 }; 00054 00055 class CaseCollector : public RecursiveASTVisitor<CaseCollector> { 00056 ParentMap &PMap; 00057 SmallVectorImpl<CaseInfo> &Cases; 00058 00059 public: 00060 CaseCollector(ParentMap &PMap, SmallVectorImpl<CaseInfo> &Cases) 00061 : PMap(PMap), Cases(Cases) { } 00062 00063 bool VisitSwitchStmt(SwitchStmt *S) { 00064 SwitchCase *Curr = S->getSwitchCaseList(); 00065 if (!Curr) 00066 return true; 00067 Stmt *Parent = getCaseParent(Curr); 00068 Curr = Curr->getNextSwitchCase(); 00069 // Make sure all case statements are in the same scope. 00070 while (Curr) { 00071 if (getCaseParent(Curr) != Parent) 00072 return true; 00073 Curr = Curr->getNextSwitchCase(); 00074 } 00075 00076 SourceLocation NextLoc = S->getLocEnd(); 00077 Curr = S->getSwitchCaseList(); 00078 // We iterate over case statements in reverse source-order. 00079 while (Curr) { 00080 Cases.push_back(CaseInfo(Curr,SourceRange(Curr->getLocStart(), NextLoc))); 00081 NextLoc = Curr->getLocStart(); 00082 Curr = Curr->getNextSwitchCase(); 00083 } 00084 return true; 00085 } 00086 00087 Stmt *getCaseParent(SwitchCase *S) { 00088 Stmt *Parent = PMap.getParent(S); 00089 while (Parent && (isa<SwitchCase>(Parent) || isa<LabelStmt>(Parent))) 00090 Parent = PMap.getParent(Parent); 00091 return Parent; 00092 } 00093 }; 00094 00095 class ProtectedScopeFixer { 00096 MigrationPass &Pass; 00097 SourceManager &SM; 00098 SmallVector<CaseInfo, 16> Cases; 00099 SmallVector<DeclRefExpr *, 16> LocalRefs; 00100 00101 public: 00102 ProtectedScopeFixer(BodyContext &BodyCtx) 00103 : Pass(BodyCtx.getMigrationContext().Pass), 00104 SM(Pass.Ctx.getSourceManager()) { 00105 00106 CaseCollector(BodyCtx.getParentMap(), Cases) 00107 .TraverseStmt(BodyCtx.getTopStmt()); 00108 LocalRefsCollector(LocalRefs).TraverseStmt(BodyCtx.getTopStmt()); 00109 00110 SourceRange BodyRange = BodyCtx.getTopStmt()->getSourceRange(); 00111 const CapturedDiagList &DiagList = Pass.getDiags(); 00112 // Copy the diagnostics so we don't have to worry about invaliding iterators 00113 // from the diagnostic list. 00114 SmallVector<StoredDiagnostic, 16> StoredDiags; 00115 StoredDiags.append(DiagList.begin(), DiagList.end()); 00116 SmallVectorImpl<StoredDiagnostic>::iterator 00117 I = StoredDiags.begin(), E = StoredDiags.end(); 00118 while (I != E) { 00119 if (I->getID() == diag::err_switch_into_protected_scope && 00120 isInRange(I->getLocation(), BodyRange)) { 00121 handleProtectedScopeError(I, E); 00122 continue; 00123 } 00124 ++I; 00125 } 00126 } 00127 00128 void handleProtectedScopeError( 00129 SmallVectorImpl<StoredDiagnostic>::iterator &DiagI, 00130 SmallVectorImpl<StoredDiagnostic>::iterator DiagE){ 00131 Transaction Trans(Pass.TA); 00132 assert(DiagI->getID() == diag::err_switch_into_protected_scope); 00133 SourceLocation ErrLoc = DiagI->getLocation(); 00134 bool handledAllNotes = true; 00135 ++DiagI; 00136 for (; DiagI != DiagE && DiagI->getLevel() == DiagnosticsEngine::Note; 00137 ++DiagI) { 00138 if (!handleProtectedNote(*DiagI)) 00139 handledAllNotes = false; 00140 } 00141 00142 if (handledAllNotes) 00143 Pass.TA.clearDiagnostic(diag::err_switch_into_protected_scope, ErrLoc); 00144 } 00145 00146 bool handleProtectedNote(const StoredDiagnostic &Diag) { 00147 assert(Diag.getLevel() == DiagnosticsEngine::Note); 00148 00149 for (unsigned i = 0; i != Cases.size(); i++) { 00150 CaseInfo &info = Cases[i]; 00151 if (isInRange(Diag.getLocation(), info.Range)) { 00152 00153 if (info.State == CaseInfo::St_Unchecked) 00154 tryFixing(info); 00155 assert(info.State != CaseInfo::St_Unchecked); 00156 00157 if (info.State == CaseInfo::St_Fixed) { 00158 Pass.TA.clearDiagnostic(Diag.getID(), Diag.getLocation()); 00159 return true; 00160 } 00161 return false; 00162 } 00163 } 00164 00165 return false; 00166 } 00167 00168 void tryFixing(CaseInfo &info) { 00169 assert(info.State == CaseInfo::St_Unchecked); 00170 if (hasVarReferencedOutside(info)) { 00171 info.State = CaseInfo::St_CannotFix; 00172 return; 00173 } 00174 00175 Pass.TA.insertAfterToken(info.SC->getColonLoc(), " {"); 00176 Pass.TA.insert(info.Range.getEnd(), "}\n"); 00177 info.State = CaseInfo::St_Fixed; 00178 } 00179 00180 bool hasVarReferencedOutside(CaseInfo &info) { 00181 for (unsigned i = 0, e = LocalRefs.size(); i != e; ++i) { 00182 DeclRefExpr *DRE = LocalRefs[i]; 00183 if (isInRange(DRE->getDecl()->getLocation(), info.Range) && 00184 !isInRange(DRE->getLocation(), info.Range)) 00185 return true; 00186 } 00187 return false; 00188 } 00189 00190 bool isInRange(SourceLocation Loc, SourceRange R) { 00191 if (Loc.isInvalid()) 00192 return false; 00193 return !SM.isBeforeInTranslationUnit(Loc, R.getBegin()) && 00194 SM.isBeforeInTranslationUnit(Loc, R.getEnd()); 00195 } 00196 }; 00197 00198 } // anonymous namespace 00199 00200 void ProtectedScopeTraverser::traverseBody(BodyContext &BodyCtx) { 00201 ProtectedScopeFixer Fix(BodyCtx); 00202 }