brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.4 KiB · 0f12b8b Raw
101 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 "RedundantDeclarationCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12#include "clang/Lex/Lexer.h"13 14using namespace clang::ast_matchers;15 16namespace clang::tidy::readability {17 18namespace {19 20AST_MATCHER(FunctionDecl, doesDeclarationForceExternallyVisibleDefinition) {21  return Node.doesDeclarationForceExternallyVisibleDefinition();22}23 24} // namespace25 26RedundantDeclarationCheck::RedundantDeclarationCheck(StringRef Name,27                                                     ClangTidyContext *Context)28    : ClangTidyCheck(Name, Context),29      IgnoreMacros(Options.get("IgnoreMacros", true)) {}30 31void RedundantDeclarationCheck::storeOptions(32    ClangTidyOptions::OptionMap &Opts) {33  Options.store(Opts, "IgnoreMacros", IgnoreMacros);34}35 36void RedundantDeclarationCheck::registerMatchers(MatchFinder *Finder) {37  Finder->addMatcher(38      namedDecl(anyOf(varDecl(unless(isDefinition())),39                      functionDecl(unless(anyOf(40                          isDefinition(), isDefaulted(),41                          doesDeclarationForceExternallyVisibleDefinition(),42                          hasAncestor(friendDecl()))))),43                optionally(hasParent(linkageSpecDecl().bind("extern"))))44          .bind("Decl"),45      this);46}47 48void RedundantDeclarationCheck::check(const MatchFinder::MatchResult &Result) {49  const auto *D = Result.Nodes.getNodeAs<NamedDecl>("Decl");50  const auto *Prev = D->getPreviousDecl();51  if (!Prev)52    return;53  if (!Prev->getLocation().isValid())54    return;55  if (Prev->getLocation() == D->getLocation())56    return;57  if (IgnoreMacros &&58      (D->getLocation().isMacroID() || Prev->getLocation().isMacroID()))59    return;60  // Don't complain when the previous declaration is a friend declaration.61  for (const auto &Parent : Result.Context->getParents(*Prev))62    if (Parent.get<FriendDecl>())63      return;64 65  const SourceManager &SM = *Result.SourceManager;66 67  const bool DifferentHeaders =68      !SM.isInMainFile(D->getLocation()) &&69      !SM.isWrittenInSameFile(Prev->getLocation(), D->getLocation());70 71  bool MultiVar = false;72  if (const auto *VD = dyn_cast<VarDecl>(D)) {73    // Is this a multivariable declaration?74    for (const auto *Other : VD->getDeclContext()->decls()) {75      if (Other != D && Other->getBeginLoc() == VD->getBeginLoc()) {76        MultiVar = true;77        break;78      }79    }80  }81 82  const SourceLocation EndLoc = Lexer::getLocForEndOfToken(83      D->getSourceRange().getEnd(), 0, SM, Result.Context->getLangOpts());84  {85    auto Diag = diag(D->getLocation(), "redundant %0 declaration") << D;86    if (!MultiVar && !DifferentHeaders) {87      SourceLocation BeginLoc;88      if (const auto *Extern =89              Result.Nodes.getNodeAs<LinkageSpecDecl>("extern");90          Extern && !Extern->hasBraces())91        BeginLoc = Extern->getExternLoc();92      else93        BeginLoc = D->getSourceRange().getBegin();94 95      Diag << FixItHint::CreateRemoval(SourceRange(BeginLoc, EndLoc));96    }97  }98  diag(Prev->getLocation(), "previously declared here", DiagnosticIDs::Note);99}100} // namespace clang::tidy::readability101