//===--- PostfixOperatorCheck.cpp - clang-tidy-----------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "PostfixOperatorCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; namespace clang { namespace tidy { namespace cert { void PostfixOperatorCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher(functionDecl(hasAnyOverloadedOperatorName("++", "--"), unless(isInstantiated())) .bind("decl"), this); } void PostfixOperatorCheck::check(const MatchFinder::MatchResult &Result) { const auto *FuncDecl = Result.Nodes.getNodeAs("decl"); bool HasThis = false; if (const auto *MethodDecl = dyn_cast(FuncDecl)) HasThis = MethodDecl->isInstance(); // Check if the operator is a postfix one. if (FuncDecl->getNumParams() != (HasThis ? 1 : 2)) return; SourceRange ReturnRange = FuncDecl->getReturnTypeSourceRange(); SourceLocation Location = ReturnRange.getBegin(); if (!Location.isValid()) return; QualType ReturnType = FuncDecl->getReturnType(); // Warn when the operators return a reference. if (const auto *RefType = ReturnType->getAs()) { auto Diag = diag(Location, "overloaded %0 returns a reference instead of a " "constant object type") << FuncDecl; if (Location.isMacroID() || ReturnType->getAs() || RefType->getPointeeTypeAsWritten()->getAs()) return; QualType ReplaceType = ReturnType.getNonReferenceType().getLocalUnqualifiedType(); // The getReturnTypeSourceRange omits the qualifiers. We do not want to // duplicate the const. if (!ReturnType->getPointeeType().isConstQualified()) ReplaceType.addConst(); Diag << FixItHint::CreateReplacement( ReturnRange, ReplaceType.getAsString(Result.Context->getPrintingPolicy()) + " "); return; } if (ReturnType.isConstQualified() || ReturnType->isBuiltinType() || ReturnType->isPointerType()) return; auto Diag = diag(Location, "overloaded %0 returns a non-constant object instead of a " "constant object type") << FuncDecl; if (!Location.isMacroID() && !ReturnType->getAs()) Diag << FixItHint::CreateInsertion(Location, "const "); } } // namespace cert } // namespace tidy } // namespace clang