clang-tools 8.0.0

ConstReturnTypeCheck.cpp
Go to the documentation of this file.
1 //===--- ConstReturnTypeCheck.cpp - clang-tidy ---------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "ConstReturnTypeCheck.h"
11 #include "../utils/LexerUtils.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Lex/Lexer.h"
16 #include "llvm/ADT/Optional.h"
17
18 using namespace clang::ast_matchers;
19
20 namespace clang {
21 namespace tidy {
22 namespace readability {
23
24 // Finds the location of the qualifying `const` token in the `FunctionDecl`'s
25 // return type. Returns `None` when the return type is not `const`-qualified or
26 // `const` does not appear in `Def`'s source like when the type is an alias or a
27 // macro.
28 static llvm::Optional<Token>
29 findConstToRemove(const FunctionDecl *Def,
30 const MatchFinder::MatchResult &Result) {
31 if (!Def->getReturnType().isLocalConstQualified())
32 return None;
33
34 // Get the begin location for the function name, including any qualifiers
35 // written in the source (for out-of-line declarations). A FunctionDecl's
36 // "location" is the start of its name, so, when the name is unqualified, we
37 // use `getLocation()`.
38 SourceLocation NameBeginLoc = Def->getQualifier()
39 ? Def->getQualifierLoc().getBeginLoc()
40 : Def->getLocation();
41 // Since either of the locs can be in a macro, use `makeFileCharRange` to be
42 // sure that we have a consistent `CharSourceRange`, located entirely in the
43 // source file.
44 CharSourceRange FileRange = Lexer::makeFileCharRange(
45 CharSourceRange::getCharRange(Def->getBeginLoc(), NameBeginLoc),
46 *Result.SourceManager, Result.Context->getLangOpts());
47
48 if (FileRange.isInvalid())
49 return None;
50
51 return utils::lexer::getConstQualifyingToken(FileRange, *Result.Context,
52 *Result.SourceManager);
53 }
54
55 namespace {
56
57 struct CheckResult {
58 // Source range of the relevant `const` token in the definition being checked.
59 CharSourceRange ConstRange;
60
61 // FixItHints associated with the definition being checked.
62 llvm::SmallVector<clang::FixItHint, 4> Hints;
63
64 // Locations of any declarations that could not be fixed.
65 llvm::SmallVector<clang::SourceLocation, 4> DeclLocs;
66 };
67
68 } // namespace
69
70 // Does the actual work of the check.
71 static CheckResult checkDef(const clang::FunctionDecl *Def,
72 const MatchFinder::MatchResult &MatchResult) {
73 CheckResult Result;
74 llvm::Optional<Token> Tok = findConstToRemove(Def, MatchResult);
75 if (!Tok)
76 return Result;
77
78 Result.ConstRange =
79 CharSourceRange::getCharRange(Tok->getLocation(), Tok->getEndLoc());
80 Result.Hints.push_back(FixItHint::CreateRemoval(Result.ConstRange));
81
82 // Fix the definition and any visible declarations, but don't warn
83 // seperately for each declaration. Instead, associate all fixes with the
84 // single warning at the definition.
85 for (const FunctionDecl *Decl = Def->getPreviousDecl(); Decl != nullptr;
86 Decl = Decl->getPreviousDecl()) {
87 if (llvm::Optional<Token> T = findConstToRemove(Decl, MatchResult))
88 Result.Hints.push_back(FixItHint::CreateRemoval(
89 CharSourceRange::getCharRange(T->getLocation(), T->getEndLoc())));
90 else
91 // `getInnerLocStart` gives the start of the return type.
92 Result.DeclLocs.push_back(Decl->getInnerLocStart());
93 }
94 return Result;
95 }
96
97 void ConstReturnTypeCheck::registerMatchers(MatchFinder *Finder) {
98 // Find all function definitions for which the return types are `const`
99 // qualified.
100 Finder->addMatcher(
101 functionDecl(returns(isConstQualified()), isDefinition()).bind("func"),
102 this);
103 }
104
105 void ConstReturnTypeCheck::check(const MatchFinder::MatchResult &Result) {
106 const auto *Def = Result.Nodes.getNodeAs<FunctionDecl>("func");
107 CheckResult CR = checkDef(Def, Result);
108 {
109 // Clang only supports one in-flight diagnostic at a time. So, delimit the
110 // scope of `Diagnostic` to allow further diagnostics after the scope. We
111 // use `getInnerLocStart` to get the start of the return type.
112 DiagnosticBuilder Diagnostic =
113 diag(Def->getInnerLocStart(),
114 "return type %0 is 'const'-qualified at the top level, which may "
115 "reduce code readability without improving const correctness")
116 << Def->getReturnType();
117 if (CR.ConstRange.isValid())
118 Diagnostic << CR.ConstRange;
119 for (auto &Hint : CR.Hints)
120 Diagnostic << Hint;
121 }
122 for (auto Loc : CR.DeclLocs)
123 diag(Loc, "could not transform this declaration", DiagnosticIDs::Note);
124 }
125
126 } // namespace readability
127 } // namespace tidy
128 } // namespace clang
Loc
SourceLocation Loc
&#39;#&#39; location in the include directive
Definition: IncludeOrderCheck.cpp:37
clang::ast_matchers
Definition: AbseilMatcher.h:15
DeclLocs
llvm::SmallVector< clang::SourceLocation, 4 > DeclLocs
Definition: ConstReturnTypeCheck.cpp:65
clang::tidy::readability::findConstToRemove
static llvm::Optional< Token > findConstToRemove(const FunctionDecl *Def, const MatchFinder::MatchResult &Result)
Definition: ConstReturnTypeCheck.cpp:29
clang::tidy::readability::checkDef
static CheckResult checkDef(const clang::FunctionDecl *Def, const MatchFinder::MatchResult &MatchResult)
Definition: ConstReturnTypeCheck.cpp:71
Result
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
Definition: ClangdServer.cpp:60
clang::tidy::utils::lexer::getConstQualifyingToken
llvm::Optional< Token > getConstQualifyingToken(CharSourceRange Range, const ASTContext &Context, const SourceManager &SM)
Assuming that Range spans a const-qualified type, returns the const token in Range that is responsibl...
Definition: LexerUtils.cpp:96
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ChangeNamespace.cpp:18
ConstRange
CharSourceRange ConstRange
Definition: ConstReturnTypeCheck.cpp:59
ConstReturnTypeCheck.h
Hints
llvm::SmallVector< clang::FixItHint, 4 > Hints
Definition: ConstReturnTypeCheck.cpp:62