void patch(void) { int32 c; Prog *p, *q; Sym *s; int32 vexit; if(debug['v']) Bprint(&bso, "%5.2f mkfwd\n", cputime()); Bflush(&bso); mkfwd(); if(debug['v']) Bprint(&bso, "%5.2f patch\n", cputime()); Bflush(&bso); s = lookup("exit", 0); vexit = s->value; for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) curtext = p; if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) { s = p->to.sym; if(s) { if(debug['c']) Bprint(&bso, "%s calls %s\n", TNAME, s->name); switch(s->type) { default: /* diag prints TNAME first */ diag("undefined: %s", s->name); s->type = STEXT; s->value = vexit; continue; // avoid more error messages case STEXT: p->to.offset = s->value; break; case SUNDEF: p->pcond = UP; p->to.offset = 0; break; } p->to.type = D_BRANCH; } } if(p->to.type != D_BRANCH || p->pcond == UP) continue; c = p->to.offset; for(q = firstp; q != P;) { if(q->forwd != P) if(c >= q->forwd->pc) { q = q->forwd; continue; } if(c == q->pc) break; q = q->link; } if(q == P) { diag("branch out of range in %s\n%P [%s]", TNAME, p, p->to.sym ? p->to.sym->name : "<nil>"); p->to.type = D_NONE; } p->pcond = q; } for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) curtext = p; p->mark = 0; /* initialization for follow */ if(p->pcond != P && p->pcond != UP) { p->pcond = brloop(p->pcond); if(p->pcond != P) if(p->to.type == D_BRANCH) p->to.offset = p->pcond->pc; } } }
void InefficientAlgorithmCheck::check(const MatchFinder::MatchResult &Result) { const auto *AlgCall = Result.Nodes.getNodeAs<CallExpr>("IneffAlg"); const auto *IneffCont = Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("IneffCont"); bool PtrToContainer = false; if (!IneffCont) { IneffCont = Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("IneffContPtr"); PtrToContainer = true; } const llvm::StringRef IneffContName = IneffCont->getName(); const bool Unordered = IneffContName.find("unordered") != llvm::StringRef::npos; const bool Maplike = IneffContName.find("map") != llvm::StringRef::npos; // Store if the key type of the container is compatible with the value // that is searched for. QualType ValueType = AlgCall->getArg(2)->getType(); QualType KeyType = IneffCont->getTemplateArgs()[0].getAsType().getCanonicalType(); const bool CompatibleTypes = areTypesCompatible(KeyType, ValueType); // Check if the comparison type for the algorithm and the container matches. if (AlgCall->getNumArgs() == 4 && !Unordered) { const Expr *Arg = AlgCall->getArg(3); const QualType AlgCmp = Arg->getType().getUnqualifiedType().getCanonicalType(); const unsigned CmpPosition = (IneffContName.find("map") == llvm::StringRef::npos) ? 1 : 2; const QualType ContainerCmp = IneffCont->getTemplateArgs()[CmpPosition] .getAsType() .getUnqualifiedType() .getCanonicalType(); if (AlgCmp != ContainerCmp) { diag(Arg->getLocStart(), "different comparers used in the algorithm and the container"); return; } } const auto *AlgDecl = AlgCall->getDirectCallee(); if (!AlgDecl) return; if (Unordered && AlgDecl->getName().find("bound") != llvm::StringRef::npos) return; const auto *AlgParam = Result.Nodes.getNodeAs<Expr>("AlgParam"); const auto *IneffContExpr = Result.Nodes.getNodeAs<Expr>("IneffContExpr"); FixItHint Hint; SourceManager &SM = *Result.SourceManager; LangOptions LangOpts = Result.Context->getLangOpts(); CharSourceRange CallRange = CharSourceRange::getTokenRange(AlgCall->getSourceRange()); // FIXME: Create a common utility to extract a file range that the given token // sequence is exactly spelled at (without macro argument expansions etc.). // We can't use Lexer::makeFileCharRange here, because for // // #define F(x) x // x(a b c); // // it will return "x(a b c)", when given the range "a"-"c". It makes sense for // removals, but not for replacements. // // This code is over-simplified, but works for many real cases. if (SM.isMacroArgExpansion(CallRange.getBegin()) && SM.isMacroArgExpansion(CallRange.getEnd())) { CallRange.setBegin(SM.getSpellingLoc(CallRange.getBegin())); CallRange.setEnd(SM.getSpellingLoc(CallRange.getEnd())); } if (!CallRange.getBegin().isMacroID() && !Maplike && CompatibleTypes) { StringRef ContainerText = Lexer::getSourceText( CharSourceRange::getTokenRange(IneffContExpr->getSourceRange()), SM, LangOpts); StringRef ParamText = Lexer::getSourceText( CharSourceRange::getTokenRange(AlgParam->getSourceRange()), SM, LangOpts); std::string ReplacementText = (llvm::Twine(ContainerText) + (PtrToContainer ? "->" : ".") + AlgDecl->getName() + "(" + ParamText + ")") .str(); Hint = FixItHint::CreateReplacement(CallRange, ReplacementText); } diag(AlgCall->getLocStart(), "this STL algorithm call should be replaced with a container method") << Hint; }