| //===--- AvoidConstParamsInDecls.cpp - clang-tidy--------------------------===// | 
 | // | 
 | //                     The LLVM Compiler Infrastructure | 
 | // | 
 | // This file is distributed under the University of Illinois Open Source | 
 | // License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "AvoidConstParamsInDecls.h" | 
 | #include "clang/ASTMatchers/ASTMatchFinder.h" | 
 | #include "clang/ASTMatchers/ASTMatchers.h" | 
 | #include "clang/Lex/Lexer.h" | 
 | #include "llvm/ADT/Optional.h" | 
 |  | 
 | using namespace clang::ast_matchers; | 
 |  | 
 | namespace clang { | 
 | namespace tidy { | 
 | namespace readability { | 
 | namespace { | 
 |  | 
 | SourceRange getTypeRange(const ParmVarDecl &Param) { | 
 |   if (Param.getIdentifier() != nullptr) | 
 |     return SourceRange(Param.getLocStart(), | 
 |                        Param.getLocEnd().getLocWithOffset(-1)); | 
 |   return Param.getSourceRange(); | 
 | } | 
 |  | 
 | } // namespace | 
 |  | 
 | void AvoidConstParamsInDecls::registerMatchers(MatchFinder *Finder) { | 
 |   const auto ConstParamDecl = | 
 |       parmVarDecl(hasType(qualType(isConstQualified()))).bind("param"); | 
 |   Finder->addMatcher( | 
 |       functionDecl(unless(isDefinition()), | 
 |                    // Lambdas are always their own definition, but they | 
 |                    // generate a non-definition FunctionDecl too. Ignore those. | 
 |                    // Class template instantiations have a non-definition | 
 |                    // CXXMethodDecl for methods that aren't used in this | 
 |                    // translation unit. Ignore those, as the template will have | 
 |                    // already been checked. | 
 |                    unless(cxxMethodDecl(ofClass(cxxRecordDecl(anyOf( | 
 |                        isLambda(), ast_matchers::isTemplateInstantiation()))))), | 
 |                    has(typeLoc(forEach(ConstParamDecl)))) | 
 |           .bind("func"), | 
 |       this); | 
 | } | 
 |  | 
 | // Re-lex the tokens to get precise location of last 'const' | 
 | static llvm::Optional<Token> ConstTok(CharSourceRange Range, | 
 |                                       const MatchFinder::MatchResult &Result) { | 
 |   const SourceManager &Sources = *Result.SourceManager; | 
 |   std::pair<FileID, unsigned> LocInfo = | 
 |       Sources.getDecomposedLoc(Range.getBegin()); | 
 |   StringRef File = Sources.getBufferData(LocInfo.first); | 
 |   const char *TokenBegin = File.data() + LocInfo.second; | 
 |   Lexer RawLexer(Sources.getLocForStartOfFile(LocInfo.first), | 
 |                  Result.Context->getLangOpts(), File.begin(), TokenBegin, | 
 |                  File.end()); | 
 |   Token Tok; | 
 |   llvm::Optional<Token> ConstTok; | 
 |   while (!RawLexer.LexFromRawLexer(Tok)) { | 
 |     if (Sources.isBeforeInTranslationUnit(Range.getEnd(), Tok.getLocation())) | 
 |       break; | 
 |     if (Tok.is(tok::raw_identifier)) { | 
 |       IdentifierInfo &Info = Result.Context->Idents.get(StringRef( | 
 |           Sources.getCharacterData(Tok.getLocation()), Tok.getLength())); | 
 |       Tok.setIdentifierInfo(&Info); | 
 |       Tok.setKind(Info.getTokenID()); | 
 |     } | 
 |     if (Tok.is(tok::kw_const)) | 
 |       ConstTok = Tok; | 
 |   } | 
 |   return ConstTok; | 
 | } | 
 |  | 
 | void AvoidConstParamsInDecls::check(const MatchFinder::MatchResult &Result) { | 
 |   const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func"); | 
 |   const auto *Param = Result.Nodes.getNodeAs<ParmVarDecl>("param"); | 
 |  | 
 |   if (!Param->getType().isLocalConstQualified()) | 
 |     return; | 
 |  | 
 |   auto Diag = diag(Param->getLocStart(), | 
 |                    "parameter %0 is const-qualified in the function " | 
 |                    "declaration; const-qualification of parameters only has an " | 
 |                    "effect in function definitions"); | 
 |   if (Param->getName().empty()) { | 
 |     for (unsigned int i = 0; i < Func->getNumParams(); ++i) { | 
 |       if (Param == Func->getParamDecl(i)) { | 
 |         Diag << (i + 1); | 
 |         break; | 
 |       } | 
 |     } | 
 |   } else { | 
 |     Diag << Param; | 
 |   } | 
 |  | 
 |   if (Param->getLocStart().isMacroID() != Param->getLocEnd().isMacroID()) { | 
 |     // Do not offer a suggestion if the part of the variable declaration comes | 
 |     // from a macro. | 
 |     return; | 
 |   } | 
 |  | 
 |   CharSourceRange FileRange = Lexer::makeFileCharRange( | 
 |       CharSourceRange::getTokenRange(getTypeRange(*Param)), | 
 |       *Result.SourceManager, getLangOpts()); | 
 |  | 
 |   if (!FileRange.isValid()) | 
 |     return; | 
 |  | 
 |   auto Tok = ConstTok(FileRange, Result); | 
 |   if (!Tok) | 
 |     return; | 
 |   Diag << FixItHint::CreateRemoval( | 
 |       CharSourceRange::getTokenRange(Tok->getLocation(), Tok->getLocation())); | 
 | } | 
 |  | 
 | } // namespace readability | 
 | } // namespace tidy | 
 | } // namespace clang |