brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.0 KiB · 76adaa8 Raw
138 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 "RedundantInlineSpecifierCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/AST/Decl.h"12#include "clang/AST/DeclCXX.h"13#include "clang/AST/DeclTemplate.h"14#include "clang/AST/ExprCXX.h"15#include "clang/ASTMatchers/ASTMatchers.h"16#include "clang/Basic/Diagnostic.h"17#include "clang/Basic/SourceLocation.h"18#include "clang/Basic/SourceManager.h"19#include "clang/Lex/Token.h"20 21#include "../utils/LexerUtils.h"22 23using namespace clang::ast_matchers;24 25namespace clang::tidy::readability {26 27namespace {28AST_POLYMORPHIC_MATCHER(isInlineSpecified,29                        AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,30                                                        VarDecl)) {31  if (const auto *FD = dyn_cast<FunctionDecl>(&Node))32    return FD->isInlineSpecified();33  if (const auto *VD = dyn_cast<VarDecl>(&Node))34    return VD->isInlineSpecified();35  llvm_unreachable("Not a valid polymorphic type");36}37 38AST_POLYMORPHIC_MATCHER_P(isInternalLinkage,39                          AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,40                                                          VarDecl),41                          bool, StrictMode) {42  if (!StrictMode)43    return false;44  if (const auto *FD = dyn_cast<FunctionDecl>(&Node))45    return FD->getStorageClass() == SC_Static || FD->isInAnonymousNamespace();46  if (const auto *VD = dyn_cast<VarDecl>(&Node))47    return VD->isInAnonymousNamespace();48  llvm_unreachable("Not a valid polymorphic type");49}50} // namespace51 52static SourceLocation getInlineTokenLocation(SourceRange RangeLocation,53                                             const SourceManager &Sources,54                                             const LangOptions &LangOpts) {55  const SourceLocation Loc = RangeLocation.getBegin();56  if (Loc.isMacroID())57    return {};58 59  Token FirstToken;60  Lexer::getRawToken(Loc, FirstToken, Sources, LangOpts, true);61  std::optional<Token> CurrentToken = FirstToken;62  while (CurrentToken && CurrentToken->getLocation() < RangeLocation.getEnd() &&63         CurrentToken->isNot(tok::eof)) {64    if (CurrentToken->is(tok::raw_identifier) &&65        CurrentToken->getRawIdentifier() == "inline")66      return CurrentToken->getLocation();67 68    CurrentToken =69        Lexer::findNextToken(CurrentToken->getLocation(), Sources, LangOpts);70  }71  return {};72}73 74void RedundantInlineSpecifierCheck::registerMatchers(MatchFinder *Finder) {75  const auto IsPartOfRecordDecl = hasAncestor(recordDecl());76  Finder->addMatcher(77      functionDecl(isInlineSpecified(),78                   anyOf(isConstexpr(), isDeleted(),79                         allOf(isDefaulted(), IsPartOfRecordDecl),80                         isInternalLinkage(StrictMode),81                         allOf(isDefinition(), IsPartOfRecordDecl)))82          .bind("fun_decl"),83      this);84 85  if (StrictMode)86    Finder->addMatcher(87        functionTemplateDecl(88            has(functionDecl(allOf(isInlineSpecified(), isDefinition()))))89            .bind("templ_decl"),90        this);91 92  if (getLangOpts().CPlusPlus17) {93    Finder->addMatcher(94        varDecl(95            isInlineSpecified(),96            anyOf(allOf(isInternalLinkage(StrictMode),97                        unless(allOf(hasInitializer(expr()), IsPartOfRecordDecl,98                                     isStaticStorageClass()))),99                  allOf(isConstexpr(), IsPartOfRecordDecl)))100            .bind("var_decl"),101        this);102  }103}104 105template <typename T>106void RedundantInlineSpecifierCheck::handleMatchedDecl(107    const T *MatchedDecl, const SourceManager &Sources,108    const MatchFinder::MatchResult &Result, StringRef Message) {109  const SourceLocation Loc = getInlineTokenLocation(110      MatchedDecl->getSourceRange(), Sources, Result.Context->getLangOpts());111  if (Loc.isValid())112    diag(Loc, Message) << MatchedDecl << FixItHint::CreateRemoval(Loc);113}114 115void RedundantInlineSpecifierCheck::check(116    const MatchFinder::MatchResult &Result) {117  const SourceManager &Sources = *Result.SourceManager;118 119  if (const auto *MatchedDecl =120          Result.Nodes.getNodeAs<FunctionDecl>("fun_decl")) {121    handleMatchedDecl(122        MatchedDecl, Sources, Result,123        "function %0 has inline specifier but is implicitly inlined");124  } else if (const auto *MatchedDecl =125                 Result.Nodes.getNodeAs<VarDecl>("var_decl")) {126    handleMatchedDecl(127        MatchedDecl, Sources, Result,128        "variable %0 has inline specifier but is implicitly inlined");129  } else if (const auto *MatchedDecl =130                 Result.Nodes.getNodeAs<FunctionTemplateDecl>("templ_decl")) {131    handleMatchedDecl(132        MatchedDecl, Sources, Result,133        "function %0 has inline specifier but is implicitly inlined");134  }135}136 137} // namespace clang::tidy::readability138