blob: 493f6165427e0b7ddeeb8934c684f6d5ab6b834c [file] [log] [blame]
//===--- FblMemoryCheck.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 "FblMemoryCheck.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 {
class FblMemoryPPCallbacks : public PPCallbacks {
public:
explicit FblMemoryPPCallbacks(FblMemoryCheck &Check, SourceManager &SM)
: Check(Check), SM(SM) {}
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange, const FileEntry *File,
StringRef SearchPath, StringRef RelativePath,
const Module *Imported,
SrcMgr::CharacteristicKind FileType) override;
void EndOfMainFile() override;
private:
bool found = false;
CharSourceRange IncludeRange;
FblMemoryCheck &Check;
SourceManager &SM;
};
void FblMemoryPPCallbacks::InclusionDirective(
SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
StringRef SearchPath, StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) {
if (FileName == "fbl/unique_ptr.h") {
unsigned End = std::strcspn(SM.getCharacterData(HashLoc), "\n") + 1;
IncludeRange =
CharSourceRange::getCharRange(HashLoc, HashLoc.getLocWithOffset(End));
found = true;
}
}
void FblMemoryPPCallbacks::EndOfMainFile() {
// Any instance of <fbl/unique_ptr.h> should be removed, since the decls in it
// will be replaced in this check and <memory> added.
if (found) {
if (!SM.isInMainFile(IncludeRange.getBegin())) {
Check.diag(IncludeRange.getBegin(),
"including fbl/unique_ptr.h is deprecated, transitively "
"included from %0")
<< SM.getFilename(IncludeRange.getBegin())
<< FixItHint::CreateRemoval(IncludeRange);
return;
}
Check.diag(IncludeRange.getBegin(),
"including fbl/unique_ptr.h is deprecated")
<< FixItHint::CreateRemoval(IncludeRange);
}
}
void FblMemoryCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("unique_ptr")))))
.bind("unique_ptr"),
this);
Finder->addMatcher(
declRefExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("make_unique")))))
.bind("make_unique"),
this);
}
void FblMemoryCheck::registerPPCallbacks(CompilerInstance &Compiler) {
Inserter = llvm::make_unique<utils::IncludeInserter>(
Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle);
Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
Compiler.getPreprocessor().addPPCallbacks(
llvm::make_unique<FblMemoryPPCallbacks>(*this,
Compiler.getSourceManager()));
}
void FblMemoryCheck::check(const MatchFinder::MatchResult &Result) {
SourceManager &SM = *Result.SourceManager;
SourceLocation Start;
SourceLocation End;
std::string Name;
if (const auto *V = Result.Nodes.getNodeAs<ValueDecl>("unique_ptr")) {
Start = V->getBeginLoc();
End = V->getEndLoc();
Name = "unique_ptr";
} else if (const auto *V =
Result.Nodes.getNodeAs<DeclRefExpr>("make_unique")) {
Start = V->getBeginLoc();
End = V->getEndLoc();
Name = "make_unique";
}
// 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 || !Statement.startswith("fbl"))
return;
size_t LAngle = Statement.find("<");
if (LAngle != std::string::npos)
End = Start.getLocWithOffset(LAngle - 1);
DiagnosticBuilder Diag =
diag(Start, "use of fbl::%0 is deprecated, use "
"std::%1 instead")
<< Name << Name
<< FixItHint::CreateReplacement(SourceRange(Start, End), "std::" + Name);
// Add in the <unique_ptr> header, since we know this file uses it.
if (llvm::Optional<FixItHint> IncludeFixit =
Inserter->CreateIncludeInsertion(SM.getFileID(Start), "memory",
/*IsAngled=*/true)) {
Diag << *IncludeFixit;
}
}
void FblMemoryCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IncludeStyle", IncludeStyle);
}
} // namespace zircon
} // namespace tidy
} // namespace clang