/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * Based on LLVM/Clang. * * This file is distributed under the University of Illinois Open Source * License. See LICENSE.TXT for details. *
*/ #ifndef LO_CLANG_SHARED_PLUGINS
bool Indentation::TraverseSwitchStmt(SwitchStmt* switchStmt)
{
PreTraverseSwitchStmt(switchStmt); auto ret = FilteringPlugin::TraverseSwitchStmt(switchStmt);
PostTraverseSwitchStmt(switchStmt, ret); return ret;
}
bool Indentation::VisitCompoundStmt(CompoundStmt const* compoundStmt)
{ if (ignoreLocation(compoundStmt)) returntrue; // these are kind of free form if (!switchStmtBodies.empty() && switchStmtBodies.back() == compoundStmt) returntrue;
constexpr unsigned MAX = std::numeric_limits<unsigned>::max(); unsigned column = MAX;
Stmt const* firstStmt = nullptr; unsigned curLine = MAX; unsigned prevLine = MAX;
SourceLocation prevEnd; auto& SM = compiler.getSourceManager(); for (auto i = compoundStmt->body_begin(); i != compoundStmt->body_end(); ++i)
{ auto stmt = *i; autoconst actualPrevEnd = prevEnd;
prevEnd = stmt->getEndLoc(); // compute early, before below `continue`s
// these show up in macro expansions, not interesting if (isa<NullStmt>(stmt)) continue; // these are always weirdly indented if (isa<LabelStmt>(stmt)) continue;
auto stmtLoc = stmt->getBeginLoc();
StringRef macroName; bool partOfMacro = false; if (SM.isMacroArgExpansion(stmtLoc) || SM.isMacroBodyExpansion(stmtLoc))
{
partOfMacro = true;
macroName = Lexer::getImmediateMacroNameForDiagnostics(
stmtLoc, compiler.getSourceManager(), compiler.getLangOpts()); // CPPUNIT_TEST_SUITE/CPPUNIT_TEST/CPPUNIT_TEST_SUITE_END work together, so the one is indented inside the other if (macroName == "CPPUNIT_TEST_SUITE") continue; // similar thing in dbaccess/ if (macroName == "DECL_PROP_IMPL") continue; // similar thing in forms/ if (macroName == "DECL_IFACE_PROP_IMPL" || macroName == "DECL_BOOL_PROP_IMPL") continue;
stmtLoc = SM.getExpansionRange(stmtLoc).getBegin();
}
// check for comment to the left of the statement
{ constchar* p1 = SM.getCharacterData(stmtLoc);
--p1; bool foundComment = false; while (*p1 && *p1 != '\n')
{ if (*p1 == '/')
{
foundComment = true; break;
}
--p1;
} if (foundComment) continue;
}
bool invalid1 = false; bool invalid2 = false; unsigned tmpColumn = SM.getPresumedColumnNumber(stmtLoc, &invalid1); unsigned tmpLine = SM.getPresumedLineNumber(stmtLoc, &invalid2); if (invalid1 || invalid2) continue;
prevLine = curLine;
curLine = tmpLine; if (column == MAX)
{
column = tmpColumn;
firstStmt = stmt;
} elseif (curLine == prevLine)
{ // ignore multiple statements on same line
} elseif (column != tmpColumn)
{ if (containsPreprocessingConditionalInclusion(SourceRange(
locationAfterToken(compiler.getSourceManager().getExpansionLoc(actualPrevEnd)),
compiler.getSourceManager().getExpansionLoc(stmt->getBeginLoc())))) continue;
report(DiagnosticsEngine::Warning, "statement mis-aligned compared to neighbours %0",
stmtLoc)
<< macroName;
report(DiagnosticsEngine::Note, "measured against this one", firstStmt->getBeginLoc()); //getParentStmt(compoundStmt)->dump(); //stmt->dump();
}
if (!partOfMacro) if (auto ifStmt = dyn_cast<IfStmt>(stmt))
{ auto bodyStmt = ifStmt->getThen(); if (bodyStmt && !isa<CompoundStmt>(bodyStmt))
{
stmtLoc = bodyStmt->getBeginLoc();
invalid1 = false;
invalid2 = false; unsigned bodyColumn = SM.getPresumedColumnNumber(stmtLoc, &invalid1); unsigned bodyLine = SM.getPresumedLineNumber(stmtLoc, &invalid2); if (invalid1 || invalid2) returntrue;
if (bodyLine != tmpLine && bodyColumn <= tmpColumn)
report(DiagnosticsEngine::Warning, "if body should be indented", stmtLoc);
}
auto elseStmt = ifStmt->getElse(); if (elseStmt && !isa<CompoundStmt>(elseStmt) && !isa<IfStmt>(elseStmt))
{
stmtLoc = elseStmt->getBeginLoc();
invalid1 = false;
invalid2 = false; unsigned elseColumn = SM.getPresumedColumnNumber(stmtLoc, &invalid1); unsigned elseLine = SM.getPresumedLineNumber(stmtLoc, &invalid2); if (invalid1 || invalid2) returntrue; if (elseLine != tmpLine && elseColumn <= tmpColumn)
report(DiagnosticsEngine::Warning, "else body should be indented", stmtLoc);
} if (elseStmt && !isa<CompoundStmt>(bodyStmt))
{
stmtLoc = ifStmt->getElseLoc();
invalid1 = false;
invalid2 = false; unsigned elseColumn = SM.getPresumedColumnNumber(stmtLoc, &invalid1); unsigned elseLine = SM.getPresumedLineNumber(stmtLoc, &invalid2); if (invalid1 || invalid2) returntrue; if (elseLine != tmpLine && elseColumn != tmpColumn)
report(DiagnosticsEngine::Warning, "if and else not aligned", stmtLoc);
}
}
}
returntrue;
}
bool Indentation::VisitIfStmt(IfStmt const* ifStmt)
{ if (ignoreLocation(ifStmt)) returntrue;
// TODO - ignore chained if statements for now if (auto chained = ifStmt->getElse())
chainedSet.insert(chained); if (chainedSet.find(ifStmt) != chainedSet.end()) returntrue;
if (auto compoundStmt = dyn_cast_or_null<CompoundStmt>(ifStmt->getThen()))
checkCompoundStmtBraces(ifStmt, compoundStmt); // TODO - needs to be checked against the line that contains the else keyword, but not against the parent // if (auto compoundStmt = dyn_cast_or_null<CompoundStmt>(ifStmt->getElse())) // checkCompoundStmtBraces(ifStmt, compoundStmt); returntrue;
}
bool Indentation::VisitForStmt(ForStmt const* forStmt)
{ if (ignoreLocation(forStmt)) returntrue; if (chainedSet.find(forStmt) != chainedSet.end()) returntrue; if (auto compoundStmt = dyn_cast_or_null<CompoundStmt>(forStmt->getBody()))
checkCompoundStmtBraces(forStmt, compoundStmt); returntrue;
}
bool Indentation::VisitWhileStmt(WhileStmt const* whileStmt)
{ if (ignoreLocation(whileStmt)) returntrue; if (chainedSet.find(whileStmt) != chainedSet.end()) returntrue; if (auto compoundStmt = dyn_cast_or_null<CompoundStmt>(whileStmt->getBody()))
checkCompoundStmtBraces(whileStmt, compoundStmt); returntrue;
}
bool Indentation::VisitDoStmt(DoStmt const* doStmt)
{ if (ignoreLocation(doStmt)) returntrue; if (chainedSet.find(doStmt) != chainedSet.end()) returntrue; if (auto compoundStmt = dyn_cast_or_null<CompoundStmt>(doStmt->getBody()))
checkCompoundStmtBraces(doStmt, compoundStmt); returntrue;
}
bool Indentation::VisitCXXForRangeStmt(CXXForRangeStmt const* cxxForRangeStmt)
{ if (ignoreLocation(cxxForRangeStmt)) returntrue; if (chainedSet.find(cxxForRangeStmt) != chainedSet.end()) returntrue; if (auto compoundStmt = dyn_cast_or_null<CompoundStmt>(cxxForRangeStmt->getBody()))
checkCompoundStmtBraces(cxxForRangeStmt, compoundStmt); returntrue;
}
auto parentBeginLoc = parentStmt->getBeginLoc(); unsigned parentColumn = SM.getPresumedColumnNumber(parentBeginLoc, &invalid1); if (invalid1) return;
auto startBraceLoc = compoundStmt->getLBracLoc(); auto endBraceLoc = compoundStmt->getRBracLoc(); unsigned beginColumn = SM.getPresumedColumnNumber(startBraceLoc, &invalid1); unsigned beginLine = SM.getPresumedLineNumber(startBraceLoc, &invalid2); if (invalid1 || invalid2) return; unsigned endColumn = SM.getPresumedColumnNumber(endBraceLoc, &invalid1); unsigned endLine = SM.getPresumedLineNumber(endBraceLoc, &invalid2); if (invalid1 || invalid2) return; if (beginLine == endLine) return;
// check for code to the left of the starting brace bool foundCodeToLeft = false;
{ constchar* p1 = SM.getCharacterData(startBraceLoc);
--p1; while (*p1 && *p1 != '\n')
{ if (*p1 != ' ')
{
foundCodeToLeft = true; break;
}
--p1;
}
}
// if we found code to the left of the start brace, that means the end-brace needs // to line up with the start of the parent statement if (foundCodeToLeft)
{ if (parentColumn != endColumn)
{
report(DiagnosticsEngine::Warning, "end brace not aligned with beginning of statement",
endBraceLoc);
report(DiagnosticsEngine::Note, "statement beginning here", parentBeginLoc);
} return;
}
if (parentColumn != beginColumn)
{
report(DiagnosticsEngine::Warning, "start brace not aligned with beginning of parent statement", startBraceLoc);
report(DiagnosticsEngine::Note, "statement beginning here", parentBeginLoc);
} elseif (beginColumn != endColumn)
{
report(DiagnosticsEngine::Warning, "start and end brace not aligned", endBraceLoc);
report(DiagnosticsEngine::Note, "start brace here", startBraceLoc);
}
/** now check that lines inside the compoundstmt are indented */ if (!compoundStmt->size()) return; auto firstStmt = compoundStmt->body_front(); if (isa<LabelStmt>(firstStmt)) return; auto firstStmtLoc = firstStmt->getBeginLoc(); unsigned firstStmtBeginColumn = SM.getPresumedColumnNumber(firstStmtLoc, &invalid1); if (invalid1) return; if (firstStmtBeginColumn > beginColumn) return;
StringRef fn = getFilenameOfLocation(compiler.getSourceManager().getSpellingLoc(firstStmtLoc)); // this is doing code generation, so the weird layout is deliberate if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sc/source/core/opencl/")) return;
report(DiagnosticsEngine::Warning, "body inside brace not indented", firstStmtLoc);
}
bool Indentation::VisitSwitchStmt(SwitchStmt const* switchStmt)
{ if (ignoreLocation(switchStmt)) returntrue;
constexpr unsigned MAX = std::numeric_limits<unsigned>::max(); unsigned column = MAX;
Stmt const* firstStmt = nullptr; unsigned curLine = MAX; unsigned prevLine = MAX; auto& SM = compiler.getSourceManager(); auto compoundStmt = dyn_cast<CompoundStmt>(switchStmt->getBody()); if (!compoundStmt) returntrue; for (auto i = compoundStmt->body_begin(); i != compoundStmt->body_end(); ++i)
{
Stmt const* caseStmt = dyn_cast<CaseStmt>(*i); if (!caseStmt)
caseStmt = dyn_cast<DefaultStmt>(*i); if (!caseStmt) continue;
auto stmtLoc = caseStmt->getBeginLoc();
bool invalid1 = false; bool invalid2 = false; unsigned tmpColumn = SM.getPresumedColumnNumber(stmtLoc, &invalid1); unsigned tmpLine = SM.getPresumedLineNumber(stmtLoc, &invalid2); if (invalid1 || invalid2) continue;
prevLine = curLine;
curLine = tmpLine; if (column == MAX)
{
column = tmpColumn;
firstStmt = caseStmt;
} elseif (curLine == prevLine)
{ // ignore multiple statements on same line
} elseif (column != tmpColumn)
{ // disable this for now, ends up touching some very large switch statements in sw/ and sc/
(void)firstStmt; // report(DiagnosticsEngine::Warning, "statement mis-aligned compared to neighbours", // stmtLoc); // report(DiagnosticsEngine::Note, "measured against this one", // firstStmt->getBeginLoc()); //getParentStmt(compoundStmt)->dump(); //stmt->dump();
}
} returntrue;
}
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.