clang-tools  10.0.0
AvoidConstParamsInDecls.cpp
Go to the documentation of this file.
1 //===--- AvoidConstParamsInDecls.cpp - clang-tidy--------------------------===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 #include "clang/ASTMatchers/ASTMatchFinder.h"
11 #include "clang/ASTMatchers/ASTMatchers.h"
12 #include "clang/Lex/Lexer.h"
13 #include "llvm/ADT/Optional.h"
14 
15 using namespace clang::ast_matchers;
16 
17 namespace clang {
18 namespace tidy {
19 namespace readability {
20 namespace {
21 
22 SourceRange getTypeRange(const ParmVarDecl &Param) {
23  if (Param.getIdentifier() != nullptr)
24  return SourceRange(Param.getBeginLoc(),
25  Param.getEndLoc().getLocWithOffset(-1));
26  return Param.getSourceRange();
27 }
28 
29 } // namespace
30 
31 void AvoidConstParamsInDecls::registerMatchers(MatchFinder *Finder) {
32  const auto ConstParamDecl =
33  parmVarDecl(hasType(qualType(isConstQualified()))).bind("param");
34  Finder->addMatcher(
35  functionDecl(unless(isDefinition()),
36  // Lambdas are always their own definition, but they
37  // generate a non-definition FunctionDecl too. Ignore those.
38  // Class template instantiations have a non-definition
39  // CXXMethodDecl for methods that aren't used in this
40  // translation unit. Ignore those, as the template will have
41  // already been checked.
42  unless(cxxMethodDecl(ofClass(cxxRecordDecl(anyOf(
43  isLambda(), ast_matchers::isTemplateInstantiation()))))),
44  has(typeLoc(forEach(ConstParamDecl))))
45  .bind("func"),
46  this);
47 }
48 
49 // Re-lex the tokens to get precise location of last 'const'
50 static llvm::Optional<Token> ConstTok(CharSourceRange Range,
51  const MatchFinder::MatchResult &Result) {
52  const SourceManager &Sources = *Result.SourceManager;
53  std::pair<FileID, unsigned> LocInfo =
54  Sources.getDecomposedLoc(Range.getBegin());
55  StringRef File = Sources.getBufferData(LocInfo.first);
56  const char *TokenBegin = File.data() + LocInfo.second;
57  Lexer RawLexer(Sources.getLocForStartOfFile(LocInfo.first),
58  Result.Context->getLangOpts(), File.begin(), TokenBegin,
59  File.end());
60  Token Tok;
61  llvm::Optional<Token> ConstTok;
62  while (!RawLexer.LexFromRawLexer(Tok)) {
63  if (Sources.isBeforeInTranslationUnit(Range.getEnd(), Tok.getLocation()))
64  break;
65  if (Tok.is(tok::raw_identifier)) {
66  IdentifierInfo &Info = Result.Context->Idents.get(StringRef(
67  Sources.getCharacterData(Tok.getLocation()), Tok.getLength()));
68  Tok.setIdentifierInfo(&Info);
69  Tok.setKind(Info.getTokenID());
70  }
71  if (Tok.is(tok::kw_const))
72  ConstTok = Tok;
73  }
74  return ConstTok;
75 }
76 
77 void AvoidConstParamsInDecls::check(const MatchFinder::MatchResult &Result) {
78  const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
79  const auto *Param = Result.Nodes.getNodeAs<ParmVarDecl>("param");
80 
81  if (!Param->getType().isLocalConstQualified())
82  return;
83 
84  auto Diag = diag(Param->getBeginLoc(),
85  "parameter %0 is const-qualified in the function "
86  "declaration; const-qualification of parameters only has an "
87  "effect in function definitions");
88  if (Param->getName().empty()) {
89  for (unsigned int i = 0; i < Func->getNumParams(); ++i) {
90  if (Param == Func->getParamDecl(i)) {
91  Diag << (i + 1);
92  break;
93  }
94  }
95  } else {
96  Diag << Param;
97  }
98 
99  if (Param->getBeginLoc().isMacroID() != Param->getEndLoc().isMacroID()) {
100  // Do not offer a suggestion if the part of the variable declaration comes
101  // from a macro.
102  return;
103  }
104 
105  CharSourceRange FileRange = Lexer::makeFileCharRange(
106  CharSourceRange::getTokenRange(getTypeRange(*Param)),
107  *Result.SourceManager, getLangOpts());
108 
109  if (!FileRange.isValid())
110  return;
111 
112  auto Tok = ConstTok(FileRange, Result);
113  if (!Tok)
114  return;
115  Diag << FixItHint::CreateRemoval(
116  CharSourceRange::getTokenRange(Tok->getLocation(), Tok->getLocation()));
117 }
118 
119 } // namespace readability
120 } // namespace tidy
121 } // namespace clang
static llvm::Optional< Token > ConstTok(CharSourceRange Range, const MatchFinder::MatchResult &Result)
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
Definition: SourceCode.cpp:227
FunctionInfo Info
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
CharSourceRange Range
SourceRange for the file name.