summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2017-09-21 11:06:43 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2017-09-21 15:29:20 +0200
commit3a481dde031ba416ec4ef0351130e26e49417418 (patch)
treeabfec5320c66e8c28b3da01852c531ef4a7ce0eb /compilerplugins
parentac80f048f2bb23651ddc3c6608e9ef24635698d7 (diff)
loplugin:flatten in editeng..extensions
Change-Id: I2b68f5640471ea827c09af1b5a319fb526a53b4b Reviewed-on: https://gerrit.libreoffice.org/42579 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'compilerplugins')
-rw-r--r--compilerplugins/clang/flatten.cxx125
1 files changed, 91 insertions, 34 deletions
diff --git a/compilerplugins/clang/flatten.cxx b/compilerplugins/clang/flatten.cxx
index 4e031ef1f3a5..145311144fee 100644
--- a/compilerplugins/clang/flatten.cxx
+++ b/compilerplugins/clang/flatten.cxx
@@ -37,6 +37,7 @@ public:
private:
bool rewrite(const IfStmt * );
SourceRange ignoreMacroExpansions(SourceRange range);
+ SourceRange extendOverComments(SourceRange range);
std::string getSourceAsString(SourceRange range);
};
@@ -101,8 +102,9 @@ bool Flatten::VisitIfStmt(const IfStmt* ifStmt)
}
static std::string stripOpenAndCloseBrace(std::string s);
-static std::string deindentThenStmt(std::string const & s);
-static std::vector<std::string> split(std::string const & s);
+static std::string deindent(std::string const & s);
+static std::vector<std::string> split(std::string s);
+static bool startswith(const std::string& rStr, const char* pSubStr);
bool Flatten::rewrite(const IfStmt* ifStmt)
{
@@ -121,12 +123,22 @@ bool Flatten::rewrite(const IfStmt* ifStmt)
if (!elseRange.isValid()) {
return false;
}
- auto elseKeywordRange = ifStmt->getElseLoc();
+ SourceRange elseKeywordRange = ifStmt->getElseLoc();
+
+ thenRange = extendOverComments(thenRange);
+ elseRange = extendOverComments(elseRange);
+ elseKeywordRange = extendOverComments(elseKeywordRange);
// in adjusting the formatting I assume that "{" starts on a new line
std::string conditionString = getSourceAsString(conditionRange);
- conditionString = "!(" + conditionString + ")";
+ auto condExpr = ifStmt->getCond()->IgnoreImpCasts();
+ if (auto exprWithCleanups = dyn_cast<ExprWithCleanups>(condExpr))
+ condExpr = exprWithCleanups->getSubExpr()->IgnoreImpCasts();
+ if (isa<DeclRefExpr>(condExpr) || isa<CallExpr>(condExpr) || isa<MemberExpr>(condExpr))
+ conditionString = "!" + conditionString;
+ else
+ conditionString = "!(" + conditionString + ")";
std::string thenString = getSourceAsString(thenRange);
bool thenIsCompound = false;
@@ -136,23 +148,14 @@ bool Flatten::rewrite(const IfStmt* ifStmt)
thenString = stripOpenAndCloseBrace(thenString);
}
}
- thenString = deindentThenStmt(thenString);
+ thenString = deindent(thenString);
std::string elseString = getSourceAsString(elseRange);
- bool elseIsCompound = false;
- if (auto compoundStmt = dyn_cast<CompoundStmt>(ifStmt->getElse())) {
- if (compoundStmt->getLBracLoc().isValid()) {
- elseIsCompound = true;
- }
- }
- // indent else block if necessary
- if (thenIsCompound && !elseIsCompound)
- elseString = " " + elseString;
if (!replaceText(elseRange, thenString)) {
return false;
}
- if (!replaceText(elseKeywordRange, "")) {
+ if (!removeText(elseKeywordRange, RewriteOptions(RemoveLineIfEmpty))) {
return false;
}
if (!replaceText(thenRange, elseString)) {
@@ -167,38 +170,44 @@ bool Flatten::rewrite(const IfStmt* ifStmt)
std::string stripOpenAndCloseBrace(std::string s)
{
- size_t openBrace = s.find_first_of("{");
- if (openBrace != std::string::npos) {
- size_t openLineEnd = s.find_first_of("\n", openBrace + 1);
- if (openLineEnd != std::string::npos)
- s = s.substr(openLineEnd + 1);
- else
- s = s.substr(openBrace + 1);
+ size_t i = s.find("{");
+ if (i != std::string::npos) {
+ ++i;
+ // strip to line end
+ while (s[i] == ' ')
+ ++i;
+ if (s[i] == '\n')
+ ++i;
+ s = s.substr(i);
}
- size_t closeBrace = s.find_last_of("}");
- if (closeBrace != std::string::npos) {
- size_t closeLineEnd = s.find_last_of("\n", closeBrace);
- if (closeLineEnd != std::string::npos)
- s = s.substr(0, closeLineEnd - 1);
- else
- s = s.substr(0, closeBrace - 1);
+ i = s.rfind("}");
+ if (i != std::string::npos) {
+ --i;
+ while (s[i] == ' ')
+ --i;
+ s = s.substr(0,i);
}
return s;
}
-std::string deindentThenStmt(std::string const & s)
+std::string deindent(std::string const & s)
{
std::vector<std::string> lines = split(s);
std::string rv;
for (auto s : lines) {
- rv += s.length() > 4 ? s.substr(4) : s;
+ if (startswith(s, " "))
+ rv += s.substr(4);
+ else
+ rv += s;
rv += "\n";
}
return rv;
}
-std::vector<std::string> split(std::string const & 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
@@ -211,6 +220,11 @@ std::vector<std::string> split(std::string const & s)
return rv;
}
+static bool startswith(const std::string& rStr, const char* pSubStr)
+{
+ return rStr.compare(0, strlen(pSubStr), pSubStr) == 0;
+}
+
SourceRange Flatten::ignoreMacroExpansions(SourceRange range) {
while (compiler.getSourceManager().isMacroArgExpansion(range.getBegin())) {
range.setBegin(
@@ -244,6 +258,49 @@ SourceRange Flatten::ignoreMacroExpansions(SourceRange range) {
? SourceRange() : range;
}
+/**
+ * Extend the SourceRange to include any leading and trailing whitespace, and any comments.
+ */
+SourceRange Flatten::extendOverComments(SourceRange range)
+{
+ SourceManager& SM = compiler.getSourceManager();
+ SourceLocation startLoc = range.getBegin();
+ SourceLocation endLoc = range.getEnd();
+ const char *p1 = SM.getCharacterData( startLoc );
+ const char *p2 = SM.getCharacterData( endLoc );
+
+ // scan backwards from the beginning to include any spaces on that line
+ while (*(p1-1) == ' ')
+ --p1;
+ startLoc = startLoc.getLocWithOffset(p1 - SM.getCharacterData( startLoc ));
+
+ p2 += Lexer::MeasureTokenLength( endLoc, SM, compiler.getLangOpts());
+ // look for trailing ";"
+ while (*p2 == ';')
+ ++p2;
+ // look for trailing " "
+ while (*p2 == ' ')
+ ++p2;
+ // look for single line comments attached to the end of the statement
+ if (*p2 == '/' && *(p2+1) == '/')
+ {
+ p2 += 2;
+ while (*p2 && *p2 != '\n')
+ ++p2;
+ if (*p2 == '\n')
+ ++p2;
+ }
+ else
+ {
+ // make the source code we extract include any trailing "\n"
+ if (*p2 == '\n')
+ ++p2;
+ }
+ endLoc = endLoc.getLocWithOffset(p2 - SM.getCharacterData( endLoc ));
+
+ return SourceRange(startLoc, endLoc);
+}
+
std::string Flatten::getSourceAsString(SourceRange range)
{
SourceManager& SM = compiler.getSourceManager();
@@ -251,8 +308,8 @@ std::string Flatten::getSourceAsString(SourceRange range)
SourceLocation endLoc = range.getEnd();
const char *p1 = SM.getCharacterData( startLoc );
const char *p2 = SM.getCharacterData( endLoc );
- unsigned n = Lexer::MeasureTokenLength( endLoc, SM, compiler.getLangOpts());
- return std::string( p1, p2 - p1 + n);
+ p2 += Lexer::MeasureTokenLength( endLoc, SM, compiler.getLangOpts());
+ return std::string( p1, p2 - p1);
}
loplugin::Plugin::Registration< Flatten > X("flatten", false);