staticbool containsVarDecl(Stmt const * stmt)
{ if (auto compoundStmt = dyn_cast<CompoundStmt>(stmt)) { for (auto i = compoundStmt->body_begin(); i != compoundStmt->body_end(); ++i) { auto declStmt = dyn_cast<DeclStmt>(*i); if (declStmt && isa<VarDecl>(*declStmt->decl_begin())) returntrue;
} returnfalse;
} auto declStmt = dyn_cast<DeclStmt>(stmt); return declStmt && isa<VarDecl>(*declStmt->decl_begin());
}
bool Flatten::TraverseCXXCatchStmt(CXXCatchStmt* )
{ // ignore stuff inside catch statements, where doing a "if...else..throw" is more natural returntrue;
}
bool Flatten::TraverseIfStmt(IfStmt * ifStmt)
{ if (!WalkUpFromIfStmt(ifStmt)) { returnfalse;
} autoconst saved = mElseBranch;
mElseBranch = ifStmt->getElse(); auto ret = true; for (autoconst sub: ifStmt->children()) { if (!TraverseStmt(sub)) {
ret = false; break;
}
}
mElseBranch = saved; return ret;
}
bool Flatten::TraverseCompoundStmt(CompoundStmt * compoundStmt)
{ auto copy = lastStmtInCompoundStmt; if (compoundStmt->size() > 0)
lastStmtInCompoundStmt = compoundStmt->body_back(); else
lastStmtInCompoundStmt = nullptr;
bool Flatten::VisitIfStmt(IfStmt const * ifStmt)
{ if (ignoreLocation(ifStmt)) returntrue;
// ignore if we are part of an if/then/else/if chain if (ifStmt == mElseBranch || (ifStmt->getElse() && isa<IfStmt>(ifStmt->getElse()))) returntrue;
// look for a large if(){} block at the end of a function if (!ifStmt->getElse()
&& (functionDecl->getReturnType().isNull() || functionDecl->getReturnType()->isVoidType())
&& functionDeclBody && functionDeclBody->size()
&& functionDeclBody->body_back() == ifStmt
&& isLargeCompoundStmt(ifStmt->getThen()))
{ if (!rewriteLargeIf(ifStmt))
{
report(
DiagnosticsEngine::Warning, "large if statement at end of function, rather invert the condition and exit early, and flatten the function",
ifStmt->getBeginLoc())
<< ifStmt->getSourceRange();
} returntrue;
}
if (!ifStmt->getElse()) returntrue;
autoconst thenThrowExpr = containsSingleThrowExpr(ifStmt->getThen()); autoconst elseThrowExpr = containsSingleThrowExpr(ifStmt->getElse()); // If neither contains a throw, nothing to do; if both contain throws, no // improvement: if ((thenThrowExpr == nullptr) == (elseThrowExpr == nullptr)) { returntrue;
}
if (containsPreprocessingConditionalInclusion(ifStmt->getSourceRange())) { returntrue;
}
if (elseThrowExpr)
{ // if the "if" statement is not the last statement in its block, and it contains // var decls in its then block, we cannot de-indent the then block without // extending the lifetime of some variables, which may be problematic if (ifStmt != lastStmtInCompoundStmt && containsVarDecl(ifStmt->getThen())) returntrue;
if (!rewrite1(ifStmt))
{
report(
DiagnosticsEngine::Warning, "unconditional throw in else branch, rather invert the condition, throw early, and flatten the normal case",
elseThrowExpr->getBeginLoc())
<< elseThrowExpr->getSourceRange();
report(
DiagnosticsEngine::Note, "if condition here",
ifStmt->getBeginLoc())
<< ifStmt->getSourceRange();
}
} if (thenThrowExpr)
{ // if the "if" statement is not the last statement in its block, and it contains // var decls in its else block, we cannot de-indent the else block without // extending the lifetime of some variables, which may be problematic if (ifStmt != lastStmtInCompoundStmt && containsVarDecl(ifStmt->getElse())) returntrue;
if (!rewrite2(ifStmt))
{
report(
DiagnosticsEngine::Warning, "unconditional throw in then branch, just flatten the else",
thenThrowExpr->getBeginLoc())
<< thenThrowExpr->getSourceRange();
}
} returntrue;
}
if (!replaceText(elseRange, elseString)) { returnfalse;
} if (!removeText(elseKeywordRange)) { returnfalse;
}
returntrue;
}
bool Flatten::rewriteLargeIf(IfStmt const * ifStmt)
{ if (!rewriter) returnfalse;
auto conditionRange = ignoreMacroExpansions(ifStmt->getCond()->getSourceRange()); if (!conditionRange.isValid()) { returnfalse;
} auto thenRange = ignoreMacroExpansions(ifStmt->getThen()->getSourceRange()); if (!thenRange.isValid()) { returnfalse;
}
thenRange = extendOverComments(thenRange);
// in adjusting the formatting I assume that "{" starts on a new line
compat::optional<std::string> conditionString = invertCondition(ifStmt->getCond(), conditionRange); if (!conditionString) returnfalse;
if (auto exprWithCleanups = dyn_cast<ExprWithCleanups>(condExpr))
condExpr = exprWithCleanups->getSubExpr()->IgnoreImpCasts();
// an if statement will automatically invoke a bool-conversion method if (auto memberCallExpr = dyn_cast<CXXMemberCallExpr>(condExpr))
{ if (memberCallExpr->getMethodDecl() && isa<CXXConversionDecl>(memberCallExpr->getMethodDecl()))
condExpr = memberCallExpr->getImplicitObjectArgument()->IgnoreImpCasts();
}
if (auto unaryOp = dyn_cast<UnaryOperator>(condExpr))
{ if (unaryOp->getOpcode() != UO_LNot) return"!(" + s + ")"; auto i = s.find("!");
assert (i != std::string::npos);
s = s.substr(i+1);
} elseif (auto binaryOp = dyn_cast<BinaryOperator>(condExpr))
{ bool ok = true; switch (binaryOp->getOpcode())
{ case BO_LT: ok = replace(s, "<", ">="); break; case BO_GT: ok = replace(s, ">", "<="); break; case BO_LE: ok = replace(s, "<=", ">"); break; case BO_GE: ok = replace(s, ">=", "<"); break; case BO_EQ: ok = replace(s, "==", "!="); break; case BO_NE: ok = replace(s, "!=", "=="); break; default:
s = "!(" + s + ")";
} if (!ok) return compat::optional<std::string>();
} elseif (auto opCallExpr = dyn_cast<CXXOperatorCallExpr>(condExpr))
{ bool ok = true; switch (opCallExpr->getOperator())
{ case OO_Less: ok = replace(s, "<", ">="); break; case OO_Greater: ok = replace(s, ">", "<="); break; case OO_LessEqual: ok = replace(s, "<=", ">"); break; case OO_GreaterEqual: ok = replace(s, ">=", "<"); break; case OO_EqualEqual: ok = replace(s, "==", "!="); break; case OO_ExclaimEqual: ok = replace(s, "!=", "=="); break; default:
s = "!(" + s + ")";
} if (!ok) return compat::optional<std::string>();
} elseif (isa<DeclRefExpr>(condExpr) || isa<CallExpr>(condExpr) || isa<MemberExpr>(condExpr))
s = "!" + s; else
s = "!(" + s + ")"; return s;
}
std::string stripOpenAndCloseBrace(std::string s)
{
size_t i = s.find("{"); if (i == std::string::npos)
{
assert( !"did not find {" );
abort();
}
++i; // strip to line end while (s[i] == ' ')
++i; if (s[i] == '\n')
++i;
s = s.substr(i);
i = s.rfind("}"); if (i == std::string::npos)
{
assert( !"did not find }" );
abort();
}
--i; while (s[i] == ' ')
--i;
s = s.substr(0,i); return s;
}
std::vector<std::string> split(std::string s)
{ if (s.back() == '\n')
s = s.substr(0, s.size()-1);
size_t next = -1;
std::vector<std::string> rv; do
{
size_t current = next + 1;
next = s.find_first_of( "\n", current );
rv.push_back(s.substr( current, next - current ));
} while (next != std::string::npos); return rv;
}
bool replace(std::string & s, std::string const & from, std::string const & to)
{ auto i = s.find(from);
assert (i != std::string::npos);
s.replace(i, from.length(), to); // just in case we have something really weird, like the operator token is also present in the rest of the condition somehow return s.find(from) == std::string::npos;
}
SourceRange Flatten::ignoreMacroExpansions(SourceRange range) { while (compiler.getSourceManager().isMacroArgExpansion(range.getBegin())) {
range.setBegin(
compiler.getSourceManager().getImmediateMacroCallerLoc(
range.getBegin()));
} if (range.getBegin().isMacroID()) {
SourceLocation loc; if (Lexer::isAtStartOfMacroExpansion(
range.getBegin(), compiler.getSourceManager(),
compiler.getLangOpts(), &loc))
{
range.setBegin(loc);
}
} while (compiler.getSourceManager().isMacroArgExpansion(range.getEnd())) {
range.setEnd(
compiler.getSourceManager().getImmediateMacroCallerLoc(
range.getEnd()));
} if (range.getEnd().isMacroID()) {
SourceLocation loc; if (Lexer::isAtEndOfMacroExpansion(
range.getEnd(), compiler.getSourceManager(),
compiler.getLangOpts(), &loc))
{
range.setEnd(loc);
}
} return range.getBegin().isMacroID() || range.getEnd().isMacroID()
? SourceRange() : range;
}
// scan backwards from the beginning to include any spaces on that line while (*(p1-1) == ' ')
--p1;
startLoc = startLoc.getLocWithOffset(p1 - SM.getCharacterData( startLoc ));
// look for trailing ";" while (*(p2+1) == ';')
++p2; // look for trailing " " while (*(p2+1) == ' ')
++p2; // look for single line comments attached to the end of the statement if (*(p2+1) == '/' && *(p2+2) == '/')
{
p2 += 2; while (*(p2+1) && *(p2+1) != '\n')
++p2; if (*(p2+1) == '\n')
++p2;
} else
{ // make the source code we extract include any trailing "\n" if (*(p2+1) == '\n')
++p2;
}
endLoc = endLoc.getLocWithOffset(p2 - SM.getCharacterData( endLoc ));
return SourceRange(startLoc, endLoc);
}
std::string Flatten::getSourceAsString(SourceRange range)
{
SourceManager& SM = compiler.getSourceManager();
SourceLocation startLoc = range.getBegin();
SourceLocation endLoc = range.getEnd(); charconst *p1 = SM.getCharacterData( startLoc ); charconst *p2 = SM.getCharacterData( endLoc );
p2 += Lexer::MeasureTokenLength( endLoc, SM, compiler.getLangOpts()); if (p2 < p1) { // workaround clang weirdness, but don't return empty string // in case it happens during code replacement return"clang returned bad pointers";
} if (p2 - p1 > 64 * 1024) { // workaround clang weirdness, but don't return empty string // in case it happens during code replacement return"clang returned overlay large source range";
} return std::string( p1, p2 - p1);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.