85 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			85 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===--- 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<FunctionDecl>("decl");
 | |
| 
 | |
|   bool HasThis = false;
 | |
|   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(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<ReferenceType>()) {
 | |
|     auto Diag = diag(Location, "overloaded %0 returns a reference instead of a "
 | |
|                                "constant object type")
 | |
|                 << FuncDecl;
 | |
| 
 | |
|     if (Location.isMacroID() || ReturnType->getAs<TypedefType>() ||
 | |
|         RefType->getPointeeTypeAsWritten()->getAs<TypedefType>())
 | |
|       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<TypedefType>())
 | |
|     Diag << FixItHint::CreateInsertion(Location, "const ");
 | |
| }
 | |
| 
 | |
| } // namespace cert
 | |
| } // namespace tidy
 | |
| } // namespace clang
 |