diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy')
4 files changed, 114 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt index 7a3db102489..65eec754b3a 100644 --- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -21,6 +21,7 @@ add_clang_library(clangTidyMiscModule SizeofContainerCheck.cpp StaticAssertCheck.cpp StringIntegerAssignmentCheck.cpp + SuspiciousSemicolonCheck.cpp SwappedArgumentsCheck.cpp ThrowByValueCatchByReferenceCheck.cpp UndelegatedConstructor.cpp diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp index 16fbf2de986..efb5cb9cf24 100644 --- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -29,6 +29,7 @@ #include "SizeofContainerCheck.h" #include "StaticAssertCheck.h" #include "StringIntegerAssignmentCheck.h" +#include "SuspiciousSemicolonCheck.h" #include "SwappedArgumentsCheck.h" #include "ThrowByValueCatchByReferenceCheck.h" #include "UndelegatedConstructor.h" @@ -81,6 +82,8 @@ public: "misc-static-assert"); CheckFactories.registerCheck<StringIntegerAssignmentCheck>( "misc-string-integer-assignment"); + CheckFactories.registerCheck<SuspiciousSemicolonCheck>( + "misc-suspicious-semicolon"); CheckFactories.registerCheck<SwappedArgumentsCheck>( "misc-swapped-arguments"); CheckFactories.registerCheck<ThrowByValueCatchByReferenceCheck>( diff --git a/clang-tools-extra/clang-tidy/misc/SuspiciousSemicolonCheck.cpp b/clang-tools-extra/clang-tidy/misc/SuspiciousSemicolonCheck.cpp new file mode 100644 index 00000000000..5330f70e6ae --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/SuspiciousSemicolonCheck.cpp @@ -0,0 +1,74 @@ +//===--- 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 "../utils/LexerUtils.h" +#include "SuspiciousSemicolonCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +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) { + const auto *Semicolon = Result.Nodes.getNodeAs<NullStmt>("semi"); + SourceLocation LocStart = Semicolon->getLocStart(); + + if (LocStart.isMacroID()) + return; + + ASTContext &Ctxt = *Result.Context; + auto Token = lexer_utils::getPreviousNonCommentToken(Ctxt, LocStart); + 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; + + SourceLocation LocEnd = Semicolon->getLocEnd(); + 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; + + unsigned BaseIndent = SM.getSpellingColumnNumber(Statement->getLocStart()); + 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)); +} + +} // namespace misc +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/misc/SuspiciousSemicolonCheck.h b/clang-tools-extra/clang-tidy/misc/SuspiciousSemicolonCheck.h new file mode 100644 index 00000000000..6791ba6c7ba --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/SuspiciousSemicolonCheck.h @@ -0,0 +1,36 @@ +//===--- SuspiciousSemicolonCheck.h - clang-tidy-----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_SEMICOLON_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_SEMICOLON_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace misc { + +/// This check finds semicolon that modifies the meaning of the program +/// unintendedly. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc-suspicious-semicolon.html +class SuspiciousSemicolonCheck : public ClangTidyCheck { +public: + SuspiciousSemicolonCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_SEMICOLON_H |