brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.4 KiB · 506f8e2 Raw
99 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 "AvoidConstParamsInDeclsCheck.h"10#include "../utils/LexerUtils.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12#include "clang/ASTMatchers/ASTMatchers.h"13#include "clang/Lex/Lexer.h"14 15using namespace clang::ast_matchers;16 17namespace clang::tidy::readability {18 19static SourceRange getTypeRange(const ParmVarDecl &Param) {20  return {Param.getBeginLoc(), Param.getLocation().getLocWithOffset(-1)};21}22 23// Finds the location of the qualifying `const` token in the `ParmValDecl`'s24// return type. Returns `std::nullopt` when the parm type is not25// `const`-qualified like when the type is an alias or a macro.26static std::optional<Token>27findConstToRemove(const ParmVarDecl &Param,28                  const MatchFinder::MatchResult &Result) {29  const CharSourceRange FileRange = Lexer::makeFileCharRange(30      CharSourceRange::getTokenRange(getTypeRange(Param)),31      *Result.SourceManager, Result.Context->getLangOpts());32 33  if (FileRange.isInvalid())34    return std::nullopt;35 36  return tidy::utils::lexer::getQualifyingToken(37      tok::kw_const, FileRange, *Result.Context, *Result.SourceManager);38}39 40void AvoidConstParamsInDeclsCheck::storeOptions(41    ClangTidyOptions::OptionMap &Opts) {42  Options.store(Opts, "IgnoreMacros", IgnoreMacros);43}44 45void AvoidConstParamsInDeclsCheck::registerMatchers(MatchFinder *Finder) {46  const auto ConstParamDecl =47      parmVarDecl(hasType(qualType(isConstQualified()))).bind("param");48  Finder->addMatcher(functionDecl(unless(isDefinition()),49                                  has(typeLoc(forEach(ConstParamDecl))))50                         .bind("func"),51                     this);52}53 54void AvoidConstParamsInDeclsCheck::check(55    const MatchFinder::MatchResult &Result) {56  const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");57  const auto *Param = Result.Nodes.getNodeAs<ParmVarDecl>("param");58 59  if (!Param->getType().isLocalConstQualified())60    return;61 62  if (IgnoreMacros &&63      (Param->getBeginLoc().isMacroID() || Param->getEndLoc().isMacroID())) {64    // Suppress the check if macros are involved.65    return;66  }67 68  const auto Tok = findConstToRemove(*Param, Result);69  const auto ConstLocation = Tok ? Tok->getLocation() : Param->getBeginLoc();70 71  auto Diag = diag(ConstLocation,72                   "parameter %0 is const-qualified in the function "73                   "declaration; const-qualification of parameters only has an "74                   "effect in function definitions");75  if (Param->getName().empty()) {76    for (unsigned int I = 0; I < Func->getNumParams(); ++I) {77      if (Param == Func->getParamDecl(I)) {78        Diag << (I + 1);79        break;80      }81    }82  } else {83    Diag << Param;84  }85 86  if (Param->getBeginLoc().isMacroID() != Param->getEndLoc().isMacroID()) {87    // Do not offer a suggestion if the part of the variable declaration comes88    // from a macro.89    return;90  }91  if (!Tok)92    return;93 94  Diag << FixItHint::CreateRemoval(95      CharSourceRange::getTokenRange(Tok->getLocation(), Tok->getLocation()));96}97 98} // namespace clang::tidy::readability99