brintos

brintos / llvm-project-archived public Read only

0
0
Text · 2.8 KiB · 9d37fc1 Raw
76 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "SuspiciousSemicolonCheck.h"10#include "../utils/LexerUtils.h"11#include "clang/AST/ASTContext.h"12#include "clang/ASTMatchers/ASTMatchFinder.h"13 14using namespace clang::ast_matchers;15 16namespace clang::tidy::bugprone {17 18void SuspiciousSemicolonCheck::registerMatchers(MatchFinder *Finder) {19  Finder->addMatcher(20      stmt(anyOf(ifStmt(hasThen(nullStmt().bind("semi")),21                        unless(hasElse(stmt())), unless(isConstexpr())),22                 forStmt(hasBody(nullStmt().bind("semi"))),23                 cxxForRangeStmt(hasBody(nullStmt().bind("semi"))),24                 whileStmt(hasBody(nullStmt().bind("semi")))))25          .bind("stmt"),26      this);27}28 29void SuspiciousSemicolonCheck::check(const MatchFinder::MatchResult &Result) {30  if (Result.Context->getDiagnostics().hasUncompilableErrorOccurred())31    return;32 33  const auto *Semicolon = Result.Nodes.getNodeAs<NullStmt>("semi");34  const SourceLocation LocStart = Semicolon->getBeginLoc();35 36  if (LocStart.isMacroID())37    return;38 39  ASTContext &Ctxt = *Result.Context;40  auto Token = utils::lexer::getPreviousToken(LocStart, Ctxt.getSourceManager(),41                                              Ctxt.getLangOpts());42  auto &SM = *Result.SourceManager;43  const unsigned SemicolonLine = SM.getSpellingLineNumber(LocStart);44 45  const auto *Statement = Result.Nodes.getNodeAs<Stmt>("stmt");46  const bool IsIfStmt = isa<IfStmt>(Statement);47 48  if (!IsIfStmt &&49      SM.getSpellingLineNumber(Token.getLocation()) != SemicolonLine)50    return;51 52  const SourceLocation LocEnd = Semicolon->getEndLoc();53  const FileID FID = SM.getFileID(LocEnd);54  const llvm::MemoryBufferRef Buffer = SM.getBufferOrFake(FID, LocEnd);55  Lexer Lexer(SM.getLocForStartOfFile(FID), Ctxt.getLangOpts(),56              Buffer.getBufferStart(), SM.getCharacterData(LocEnd) + 1,57              Buffer.getBufferEnd());58  if (Lexer.LexFromRawLexer(Token))59    return;60 61  const unsigned BaseIndent =62      SM.getSpellingColumnNumber(Statement->getBeginLoc());63  const unsigned NewTokenIndent =64      SM.getSpellingColumnNumber(Token.getLocation());65  const unsigned NewTokenLine = SM.getSpellingLineNumber(Token.getLocation());66 67  if (!IsIfStmt && NewTokenIndent <= BaseIndent &&68      Token.getKind() != tok::l_brace && NewTokenLine != SemicolonLine)69    return;70 71  diag(LocStart, "potentially unintended semicolon")72      << FixItHint::CreateRemoval(SourceRange(LocStart, LocEnd));73}74 75} // namespace clang::tidy::bugprone76