clang-tools 18.0.0git
PostfixOperatorCheck.cpp
Go to the documentation of this file.
1//===--- PostfixOperatorCheck.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/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/Lex/Lexer.h"
13
14using namespace clang::ast_matchers;
15
16namespace clang::tidy::cert {
17
18void PostfixOperatorCheck::registerMatchers(MatchFinder *Finder) {
19 Finder->addMatcher(functionDecl(hasAnyOverloadedOperatorName("++", "--"),
20 unless(isInstantiated()))
21 .bind("decl"),
22 this);
23}
24
25void PostfixOperatorCheck::check(const MatchFinder::MatchResult &Result) {
26 const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("decl");
27
28 bool HasThis = false;
29 if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl))
30 HasThis = MethodDecl->isInstance();
31
32 // Check if the operator is a postfix one.
33 if (FuncDecl->getNumParams() != (HasThis ? 1 : 2))
34 return;
35
36 SourceRange ReturnRange = FuncDecl->getReturnTypeSourceRange();
37 SourceLocation Location = ReturnRange.getBegin();
38 if (!Location.isValid())
39 return;
40
41 QualType ReturnType = FuncDecl->getReturnType();
42
43 // Warn when the operators return a reference.
44 if (const auto *RefType = ReturnType->getAs<ReferenceType>()) {
45 auto Diag = diag(Location, "overloaded %0 returns a reference instead of a "
46 "constant object type")
47 << FuncDecl;
48
49 if (Location.isMacroID() || ReturnType->getAs<TypedefType>() ||
50 RefType->getPointeeTypeAsWritten()->getAs<TypedefType>())
51 return;
52
53 QualType ReplaceType =
54 ReturnType.getNonReferenceType().getLocalUnqualifiedType();
55 // The getReturnTypeSourceRange omits the qualifiers. We do not want to
56 // duplicate the const.
57 if (!ReturnType->getPointeeType().isConstQualified())
58 ReplaceType.addConst();
59
60 Diag << FixItHint::CreateReplacement(
61 ReturnRange,
62 ReplaceType.getAsString(Result.Context->getPrintingPolicy()) + " ");
63
64 return;
65 }
66
67 if (ReturnType.isConstQualified() || ReturnType->isBuiltinType() ||
68 ReturnType->isPointerType())
69 return;
70
71 auto Diag =
72 diag(Location, "overloaded %0 returns a non-constant object instead of a "
73 "constant object type")
74 << FuncDecl;
75
76 if (!Location.isMacroID() && !ReturnType->getAs<TypedefType>())
77 Diag << FixItHint::CreateInsertion(Location, "const ");
78}
79
80} // namespace clang::tidy::cert
std::string ReturnType
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.