2016-02-11 17:23:33 +08:00
|
|
|
//===--- SuspiciousSemicolonCheck.cpp - clang-tidy-------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "SuspiciousSemicolonCheck.h"
|
2016-03-03 21:08:11 +08:00
|
|
|
#include "../utils/LexerUtils.h"
|
2016-02-11 17:23:33 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
|
|
|
|
|
|
|
using namespace clang::ast_matchers;
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace tidy {
|
2018-03-01 07:47:15 +08:00
|
|
|
namespace bugprone {
|
2016-02-11 17:23:33 +08:00
|
|
|
|
|
|
|
void SuspiciousSemicolonCheck::registerMatchers(MatchFinder *Finder) {
|
|
|
|
Finder->addMatcher(
|
|
|
|
stmt(anyOf(ifStmt(hasThen(nullStmt().bind("semi")),
|
|
|
|
unless(hasElse(stmt()))),
|
|
|
|
forStmt(hasBody(nullStmt().bind("semi"))),
|
|
|
|
cxxForRangeStmt(hasBody(nullStmt().bind("semi"))),
|
|
|
|
whileStmt(hasBody(nullStmt().bind("semi")))))
|
|
|
|
.bind("stmt"),
|
|
|
|
this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SuspiciousSemicolonCheck::check(const MatchFinder::MatchResult &Result) {
|
2017-02-09 00:11:22 +08:00
|
|
|
if (Result.Context->getDiagnostics().hasUncompilableErrorOccurred())
|
2016-03-03 21:08:11 +08:00
|
|
|
return;
|
|
|
|
|
2016-02-11 17:23:33 +08:00
|
|
|
const auto *Semicolon = Result.Nodes.getNodeAs<NullStmt>("semi");
|
2018-08-10 06:42:26 +08:00
|
|
|
SourceLocation LocStart = Semicolon->getBeginLoc();
|
2016-02-11 17:23:33 +08:00
|
|
|
|
|
|
|
if (LocStart.isMacroID())
|
|
|
|
return;
|
|
|
|
|
|
|
|
ASTContext &Ctxt = *Result.Context;
|
2017-02-06 23:46:33 +08:00
|
|
|
auto Token = utils::lexer::getPreviousToken(Ctxt, LocStart);
|
2016-02-11 17:23:33 +08:00
|
|
|
auto &SM = *Result.SourceManager;
|
|
|
|
unsigned SemicolonLine = SM.getSpellingLineNumber(LocStart);
|
|
|
|
|
|
|
|
const auto *Statement = Result.Nodes.getNodeAs<Stmt>("stmt");
|
|
|
|
const bool IsIfStmt = isa<IfStmt>(Statement);
|
|
|
|
|
|
|
|
if (!IsIfStmt &&
|
|
|
|
SM.getSpellingLineNumber(Token.getLocation()) != SemicolonLine)
|
|
|
|
return;
|
|
|
|
|
2018-08-10 06:43:02 +08:00
|
|
|
SourceLocation LocEnd = Semicolon->getEndLoc();
|
2016-02-11 17:23:33 +08:00
|
|
|
FileID FID = SM.getFileID(LocEnd);
|
|
|
|
llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, LocEnd);
|
|
|
|
Lexer Lexer(SM.getLocForStartOfFile(FID), Ctxt.getLangOpts(),
|
|
|
|
Buffer->getBufferStart(), SM.getCharacterData(LocEnd) + 1,
|
|
|
|
Buffer->getBufferEnd());
|
|
|
|
if (Lexer.LexFromRawLexer(Token))
|
|
|
|
return;
|
|
|
|
|
2018-08-10 06:42:26 +08:00
|
|
|
unsigned BaseIndent = SM.getSpellingColumnNumber(Statement->getBeginLoc());
|
2016-02-11 17:23:33 +08:00
|
|
|
unsigned NewTokenIndent = SM.getSpellingColumnNumber(Token.getLocation());
|
|
|
|
unsigned NewTokenLine = SM.getSpellingLineNumber(Token.getLocation());
|
|
|
|
|
|
|
|
if (!IsIfStmt && NewTokenIndent <= BaseIndent &&
|
|
|
|
Token.getKind() != tok::l_brace && NewTokenLine != SemicolonLine)
|
|
|
|
return;
|
|
|
|
|
|
|
|
diag(LocStart, "potentially unintended semicolon")
|
|
|
|
<< FixItHint::CreateRemoval(SourceRange(LocStart, LocEnd));
|
|
|
|
}
|
|
|
|
|
2018-03-01 07:47:15 +08:00
|
|
|
} // namespace bugprone
|
2016-02-11 17:23:33 +08:00
|
|
|
} // namespace tidy
|
|
|
|
} // namespace clang
|