forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			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
 |