bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) { if (range.isInvalid()) return false; bool cleared = false; ListTy::iterator I = List.begin(); while (I != List.end()) { FullSourceLoc diagLoc = I->getLocation(); if ((IDs.empty() || // empty means clear all diagnostics in the range. std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && (diagLoc == range.getEnd() || diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { cleared = true; ListTy::iterator eraseS = I++; if (eraseS->getLevel() != DiagnosticsEngine::Note) while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note) ++I; // Clear the diagnostic and any notes following it. I = List.erase(eraseS, I); continue; } ++I; } return cleared; }
static void addParameters(ArrayRef<Identifier> &ArgNames, const ParameterList *paramList, TextEntity &Ent, SourceManager &SM, unsigned BufferID) { for (auto ¶m : *paramList) { StringRef Arg; if (!ArgNames.empty()) { Identifier Id = ArgNames.front(); Arg = Id.empty() ? "_" : Id.str(); ArgNames = ArgNames.slice(1); } if (auto typeRepr = param->getTypeLoc().getTypeRepr()) { SourceRange TypeRange = param->getTypeLoc().getSourceRange(); if (auto InOutTyR = dyn_cast_or_null<InOutTypeRepr>(typeRepr)) TypeRange = InOutTyR->getBase()->getSourceRange(); if (TypeRange.isInvalid()) continue; unsigned StartOffs = SM.getLocOffsetInBuffer(TypeRange.Start, BufferID); unsigned EndOffs = SM.getLocOffsetInBuffer(Lexer::getLocForEndOfToken(SM, TypeRange.End), BufferID); TextRange TR{ StartOffs, EndOffs-StartOffs }; TextEntity Param(param, Arg, TR, StartOffs); Ent.SubEntities.push_back(std::move(Param)); } } }
void TransformActionsImpl::increaseIndentation(SourceRange range, SourceLocation parentIndent) { if (range.isInvalid()) return; assert(IsInTransaction && "Actions only allowed during a transaction"); ActionData data; data.Kind = Act_IncreaseIndentation; data.R1 = range; data.Loc = parentIndent; CachedActions.push_back(data); }
std::pair<unsigned, unsigned> PreprocessingRecord::findLocalPreprocessedEntitiesInRange( SourceRange Range) const { if (Range.isInvalid()) return std::make_pair(0,0); assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); unsigned Begin = findBeginLocalPreprocessedEntity(Range.getBegin()); unsigned End = findEndLocalPreprocessedEntity(Range.getEnd()); return std::make_pair(Begin, End); }
bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) { if (!isRewritable(range.getBegin())) return true; if (!isRewritable(range.getEnd())) return true; if (replacementRange.isInvalid()) return true; SourceLocation start = range.getBegin(); unsigned origLength = getRangeSize(range); unsigned newLength = getRangeSize(replacementRange); FileID FID; unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(), FID); StringRef MB = SourceMgr->getBufferData(FID); return ReplaceText(start, origLength, MB.substr(newOffs, newLength)); }
void ReturnBracedInitListCheck::check(const MatchFinder::MatchResult &Result) { const auto *MatchedFunctionDecl = Result.Nodes.getNodeAs<FunctionDecl>("fn"); const auto *MatchedConstructExpr = Result.Nodes.getNodeAs<CXXConstructExpr>("ctor"); // Don't make replacements in macro. SourceLocation Loc = MatchedConstructExpr->getExprLoc(); if (Loc.isMacroID()) return; // Make sure that the return type matches the constructed type. const QualType ReturnType = MatchedFunctionDecl->getReturnType().getCanonicalType(); const QualType ConstructType = MatchedConstructExpr->getType().getCanonicalType(); if (ReturnType != ConstructType) return; auto Diag = diag(Loc, "avoid repeating the return type from the " "declaration; use a braced initializer list instead"); const SourceRange CallParensRange = MatchedConstructExpr->getParenOrBraceRange(); // Make sure there is an explicit constructor call. if (CallParensRange.isInvalid()) return; // Make sure that the ctor arguments match the declaration. for (unsigned I = 0, NumParams = MatchedConstructExpr->getNumArgs(); I < NumParams; ++I) { if (const auto *VD = dyn_cast<VarDecl>( MatchedConstructExpr->getConstructor()->getParamDecl(I))) { if (MatchedConstructExpr->getArg(I)->getType().getCanonicalType() != VD->getType().getCanonicalType()) return; } } // Range for constructor name and opening brace. CharSourceRange CtorCallSourceRange = CharSourceRange::getTokenRange( Loc, CallParensRange.getBegin().getLocWithOffset(-1)); Diag << FixItHint::CreateRemoval(CtorCallSourceRange) << FixItHint::CreateReplacement(CallParensRange.getBegin(), "{") << FixItHint::CreateReplacement(CallParensRange.getEnd(), "}"); }
/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities /// that source range \p Range encompasses. std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) { if (Range.isInvalid()) return std::make_pair(iterator(), iterator()); if (CachedRangeQuery.Range == Range) { return std::make_pair(iterator(this, CachedRangeQuery.Result.first), iterator(this, CachedRangeQuery.Result.second)); } std::pair<int, int> Res = getPreprocessedEntitiesInRangeSlow(Range); CachedRangeQuery.Range = Range; CachedRangeQuery.Result = Res; return std::make_pair(iterator(this, Res.first), iterator(this, Res.second)); }
std::vector<FixItHint> Qt4_QStringFromArray::fixitInsertFromLatin1(CXXConstructExpr *ctorExpr) { vector<FixItHint> fixits; SourceRange range; Expr *arg = *(ctorExpr->arg_begin()); range.setBegin(arg->getLocStart()); range.setEnd(Lexer::getLocForEndOfToken(FixItUtils::biggestSourceLocationInStmt(sm(), ctorExpr), 0, sm(), lo())); if (range.isInvalid()) { emitWarning(ctorExpr->getLocStart(), "Internal error"); return {}; } FixItUtils::insertParentMethodCall("QString::fromLatin1", range, fixits); return fixits; }
static void addParameters(ArrayRef<Identifier> &ArgNames, const Pattern *Pat, TextEntity &Ent, SourceManager &SM, unsigned BufferID) { if (auto ParenPat = dyn_cast<ParenPattern>(Pat)) { addParameters(ArgNames, ParenPat->getSubPattern(), Ent, SM, BufferID); return; } if (auto Tuple = dyn_cast<TuplePattern>(Pat)) { for (const auto &Elt : Tuple->getElements()) addParameters(ArgNames, Elt.getPattern(), Ent, SM, BufferID); return; } StringRef Arg; if (!ArgNames.empty()) { Identifier Id = ArgNames.front(); Arg = Id.empty() ? "_" : Id.str(); ArgNames = ArgNames.slice(1); } if (auto Typed = dyn_cast<TypedPattern>(Pat)) { VarDecl *VD = nullptr; if (auto Named = dyn_cast<NamedPattern>(Typed->getSubPattern())) { VD = Named->getDecl(); } SourceRange TypeRange = Typed->getTypeLoc().getSourceRange(); if (auto InOutTyR = dyn_cast_or_null<InOutTypeRepr>(Typed->getTypeLoc().getTypeRepr())) { TypeRange = InOutTyR->getBase()->getSourceRange(); } if (TypeRange.isInvalid()) return; unsigned StartOffs = SM.getLocOffsetInBuffer(TypeRange.Start, BufferID); unsigned EndOffs = SM.getLocOffsetInBuffer(Lexer::getLocForEndOfToken(SM, TypeRange.End), BufferID); TextRange TR{ StartOffs, EndOffs-StartOffs }; TextEntity Param(VD, Arg, TR, StartOffs); Ent.SubEntities.push_back(std::move(Param)); } }
bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs, SourceRange range) const { if (range.isInvalid()) return false; ListTy::const_iterator I = List.begin(); while (I != List.end()) { FullSourceLoc diagLoc = I->getLocation(); if ((IDs.empty() || // empty means any diagnostic in the range. std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && (diagLoc == range.getEnd() || diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { return true; } ++I; } return false; }
std::vector<FixItHint> Qt4_QStringFromArray::fixMethodCallCall(clang::CXXMemberCallExpr *memberExpr) { vector<FixItHint> fixits; if (memberExpr->getNumArgs() == 1) { Expr *e = *(memberExpr->arg_begin()); SourceLocation start = e->getLocStart(); SourceLocation end = Lexer::getLocForEndOfToken(FixItUtils::biggestSourceLocationInStmt(sm(), e), 0, sm(), lo()); SourceRange range = { start, end }; if (range.isInvalid()) { emitWarning(memberExpr->getLocStart(), "internal error"); return {}; } FixItUtils::insertParentMethodCall("QString::fromLatin1", {start, end}, /*by-ref*/fixits); } else { emitWarning(memberExpr->getLocStart(), "internal error"); } return fixits; }
void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng) const { CFGBlocksSet reachable, visited; if (Eng.hasWorkRemaining()) return; const Decl *D = nullptr; CFG *C = nullptr; ParentMap *PM = nullptr; const LocationContext *LC = nullptr; // Iterate over ExplodedGraph for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end(); I != E; ++I) { const ProgramPoint &P = I->getLocation(); LC = P.getLocationContext(); if (!LC->inTopFrame()) continue; if (!D) D = LC->getAnalysisDeclContext()->getDecl(); // Save the CFG if we don't have it already if (!C) C = LC->getAnalysisDeclContext()->getUnoptimizedCFG(); if (!PM) PM = &LC->getParentMap(); if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) { const CFGBlock *CB = BE->getBlock(); reachable.insert(CB->getBlockID()); } } // Bail out if we didn't get the CFG or the ParentMap. if (!D || !C || !PM) return; // Don't do anything for template instantiations. Proving that code // in a template instantiation is unreachable means proving that it is // unreachable in all instantiations. if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) if (FD->isTemplateInstantiation()) return; // Find CFGBlocks that were not covered by any node for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) { const CFGBlock *CB = *I; // Check if the block is unreachable if (reachable.count(CB->getBlockID())) continue; // Check if the block is empty (an artificial block) if (isEmptyCFGBlock(CB)) continue; // Find the entry points for this block if (!visited.count(CB->getBlockID())) FindUnreachableEntryPoints(CB, reachable, visited); // This block may have been pruned; check if we still want to report it if (reachable.count(CB->getBlockID())) continue; // Check for false positives if (isInvalidPath(CB, *PM)) continue; // It is good practice to always have a "default" label in a "switch", even // if we should never get there. It can be used to detect errors, for // instance. Unreachable code directly under a "default" label is therefore // likely to be a false positive. if (const Stmt *label = CB->getLabel()) if (label->getStmtClass() == Stmt::DefaultStmtClass) continue; // Special case for __builtin_unreachable. // FIXME: This should be extended to include other unreachable markers, // such as llvm_unreachable. if (!CB->empty()) { bool foundUnreachable = false; for (CFGBlock::const_iterator ci = CB->begin(), ce = CB->end(); ci != ce; ++ci) { if (Optional<CFGStmt> S = (*ci).getAs<CFGStmt>()) if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) { if (CE->getBuiltinCallee() == Builtin::BI__builtin_unreachable || CE->isBuiltinAssumeFalse(Eng.getContext())) { foundUnreachable = true; break; } } } if (foundUnreachable) continue; } // We found a block that wasn't covered - find the statement to report SourceRange SR; PathDiagnosticLocation DL; SourceLocation SL; if (const Stmt *S = getUnreachableStmt(CB)) { // In macros, 'do {...} while (0)' is often used. Don't warn about the // condition 0 when it is unreachable. if (S->getBeginLoc().isMacroID()) if (const auto *I = dyn_cast<IntegerLiteral>(S)) if (I->getValue() == 0ULL) if (const Stmt *Parent = PM->getParent(S)) if (isa<DoStmt>(Parent)) continue; SR = S->getSourceRange(); DL = PathDiagnosticLocation::createBegin(S, B.getSourceManager(), LC); SL = DL.asLocation(); if (SR.isInvalid() || !SL.isValid()) continue; } else continue; // Check if the SourceLocation is in a system header const SourceManager &SM = B.getSourceManager(); if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL)) continue; B.EmitBasicReport(D, this, "Unreachable code", "Dead code", "This statement is never executed", DL, SR); } }
void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng) const { CFGBlocksSet reachable, visited; if (Eng.hasWorkRemaining()) return; CFG *C = 0; ParentMap *PM = 0; // Iterate over ExplodedGraph for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end(); I != E; ++I) { const ProgramPoint &P = I->getLocation(); const LocationContext *LC = P.getLocationContext(); // Save the CFG if we don't have it already if (!C) C = LC->getAnalysisContext()->getUnoptimizedCFG(); if (!PM) PM = &LC->getParentMap(); if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) { const CFGBlock *CB = BE->getBlock(); reachable.insert(CB->getBlockID()); } } // Bail out if we didn't get the CFG or the ParentMap. if (!C || !PM) return; ASTContext &Ctx = B.getContext(); // Find CFGBlocks that were not covered by any node for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) { const CFGBlock *CB = *I; // Check if the block is unreachable if (reachable.count(CB->getBlockID())) continue; // Check if the block is empty (an artificial block) if (isEmptyCFGBlock(CB)) continue; // Find the entry points for this block if (!visited.count(CB->getBlockID())) FindUnreachableEntryPoints(CB, reachable, visited); // This block may have been pruned; check if we still want to report it if (reachable.count(CB->getBlockID())) continue; // Check for false positives if (CB->size() > 0 && isInvalidPath(CB, *PM)) continue; // Special case for __builtin_unreachable. // FIXME: This should be extended to include other unreachable markers, // such as llvm_unreachable. if (!CB->empty()) { CFGElement First = CB->front(); if (const CFGStmt *S = First.getAs<CFGStmt>()) { if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) { if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable) continue; } } } // We found a block that wasn't covered - find the statement to report SourceRange SR; SourceLocation SL; if (const Stmt *S = getUnreachableStmt(CB)) { SR = S->getSourceRange(); SL = S->getLocStart(); if (SR.isInvalid() || SL.isInvalid()) continue; } else continue; // Check if the SourceLocation is in a system header const SourceManager &SM = B.getSourceManager(); if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL)) continue; B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never" " executed", SL, SR); } }