1 //===--- PostfixOperatorCheck.cpp - clang-tidy-----------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "PostfixOperatorCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Lex/Lexer.h"
14 using namespace clang::ast_matchers
;
16 namespace clang::tidy::cert
{
18 void PostfixOperatorCheck::registerMatchers(MatchFinder
*Finder
) {
19 Finder
->addMatcher(functionDecl(hasAnyOverloadedOperatorName("++", "--"),
20 unless(isInstantiated()))
25 void PostfixOperatorCheck::check(const MatchFinder::MatchResult
&Result
) {
26 const auto *FuncDecl
= Result
.Nodes
.getNodeAs
<FunctionDecl
>("decl");
29 if (const auto *MethodDecl
= dyn_cast
<CXXMethodDecl
>(FuncDecl
))
30 HasThis
= MethodDecl
->isInstance();
32 // Check if the operator is a postfix one.
33 if (FuncDecl
->getNumParams() != (HasThis
? 1 : 2))
36 SourceRange ReturnRange
= FuncDecl
->getReturnTypeSourceRange();
37 SourceLocation Location
= ReturnRange
.getBegin();
38 if (!Location
.isValid())
41 QualType ReturnType
= FuncDecl
->getReturnType();
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")
49 if (Location
.isMacroID() || ReturnType
->getAs
<TypedefType
>() ||
50 RefType
->getPointeeTypeAsWritten()->getAs
<TypedefType
>())
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();
60 Diag
<< FixItHint::CreateReplacement(
62 ReplaceType
.getAsString(Result
.Context
->getPrintingPolicy()) + " ");
67 if (ReturnType
.isConstQualified() || ReturnType
->isBuiltinType() ||
68 ReturnType
->isPointerType())
72 diag(Location
, "overloaded %0 returns a non-constant object instead of a "
73 "constant object type")
76 if (!Location
.isMacroID() && !ReturnType
->getAs
<TypedefType
>())
77 Diag
<< FixItHint::CreateInsertion(Location
, "const ");
80 } // namespace clang::tidy::cert