blob: 7a023d10bbb607aa9589673c00eba4717216bafd [file] [log] [blame] [edit]
//===--- FblMoveCheck.cpp - clang-tidy ------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "FblMoveCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/Optional.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace zircon {
void FblMoveCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
callExpr(callee(functionDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("move")))))
.bind("call"),
this);
Finder->addMatcher(
callExpr(callee(functionDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("forward")))))
.bind("call"),
this);
}
void FblMoveCheck::registerPPCallbacks(CompilerInstance &Compiler) {
Inserter = llvm::make_unique<utils::IncludeInserter>(
Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle);
Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
}
void FblMoveCheck::check(const MatchFinder::MatchResult &Result) {
const auto *E = Result.Nodes.getNodeAs<CallExpr>("call");
std::string Name = E->getDirectCallee()->getNameAsString();
// Find the end of the name of the call.
SourceManager &SM = *Result.SourceManager;
SourceLocation Start = E->getBeginLoc();
SourceLocation End = E->getEndLoc();
// If it's a macro, we want to extract information about the macro instead of
// the expr.
if (Start.isMacroID()) {
Start = SM.getSpellingLoc(Start);
End = SM.getSpellingLoc(End);
}
bool Invalid = false;
StringRef Statement = Lexer::getSourceText(
CharSourceRange::getCharRange(Start, End), SM, getLangOpts(), &Invalid);
if (Invalid)
return;
// Find the template bracket, or find the lparen if the bracket isn't there.
size_t LParen = Statement.find('<');
if (LParen == std::string::npos)
LParen = Statement.find('(');
if (LParen == std::string::npos)
// If there isn't an lparen, we want the whole statement.
End = Start.getLocWithOffset(Statement.size());
else
// Remove the lparen from the size range, since we just want the call.
End = Start.getLocWithOffset(LParen - 1);
DiagnosticBuilder Diag =
diag(Start, "fbl::%0 is deprecated, use std::%1 instead")
<< Name << Name
<< FixItHint::CreateReplacement(SourceRange(Start, End), "std::" + Name);
// Add in the <utility> header.
if (llvm::Optional<FixItHint> IncludeFixit =
Inserter->CreateIncludeInsertion(SM.getFileID(Start), "utility",
/*IsAngled=*/true)) {
Diag << *IncludeFixit;
}
}
void FblMoveCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IncludeStyle", IncludeStyle);
}
} // namespace zircon
} // namespace tidy
} // namespace clang