blob: 41ceed86f2a29a57d12524f7620a3bf98b48569e [file] [log] [blame] [edit]
//===--- FblTypeTraitsCheck.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 "FblTypeTraitsCheck.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 FblTypeTraitsPPCallbacks : public PPCallbacks {
public:
explicit FblTypeTraitsPPCallbacks(FblTypeTraitsCheck &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;
FblTypeTraitsCheck &Check;
SourceManager &SM;
};
void FblTypeTraitsPPCallbacks::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/type_support.h") {
unsigned End = std::strcspn(SM.getCharacterData(HashLoc), "\n") + 1;
IncludeRange =
CharSourceRange::getCharRange(HashLoc, HashLoc.getLocWithOffset(End));
found = true;
}
}
void FblTypeTraitsPPCallbacks::EndOfMainFile() {
// Any instance of <fbl/type_support.h> should be removed, since the decls in
// it will be replaced in this check and <type_traits> added.
if (found) {
if (!SM.isInMainFile(IncludeRange.getBegin())) {
Check.diag(IncludeRange.getBegin(),
"including fbl/type_support.h is deprecated, transitively "
"included from %0")
<< SM.getFilename(IncludeRange.getBegin())
<< FixItHint::CreateRemoval(IncludeRange);
return;
}
Check.diag(IncludeRange.getBegin(),
"including fbl/type_support.h is deprecated")
<< FixItHint::CreateRemoval(IncludeRange);
}
}
void FblTypeTraitsCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("integral_constant")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("integral_constant")))))
.bind("struct"),
this);
// true_type
// false_type
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_void")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_void")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_null_pointer")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_null_pointer")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_const")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_const")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_lvalue_reference")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_lvalue_reference")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_rvalue_reference")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_rvalue_reference")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_reference")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_reference")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("remove_reference")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("remove_reference")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("remove_pointer")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("remove_pointer")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("remove_const")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("remove_const")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("remove_volatile")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("remove_volatile")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("remove_cv")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("remove_cv")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("remove_extent")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("remove_extent")))))
.bind("struct"),
this);
// move
// forward
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_same")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_same")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("enable_if")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("enable_if")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("conditional")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("conditional")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_integral")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_integral")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_floating_point")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_floating_point")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_arithmetic")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_arithmetic")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_signed")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_signed")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_unsigned")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_unsigned")))))
.bind("struct"),
this);
// is_signed_integer
// is_unsigned_integer
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_enum")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_enum")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_pod")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_pod")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_standard_layout")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_standard_layout")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("underlying_type")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("underlying_type")))))
.bind("struct"),
this);
// match_cv
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_class")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_class")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_union")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_union")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_base_of")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_base_of")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("has_virtual_destructor")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("has_virtual_destructor")))))
.bind("struct"),
this);
// has_trivial_destructor
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_pointer")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_pointer")))))
.bind("struct"),
this);
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_base_of")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_base_of")))))
.bind("struct"),
this);
// is_convertible_pointer
// trait_name (DECLARE_HAS_MEMBER_FN and DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE
// macros) void_t
Finder->addMatcher(
cxxConstructExpr(hasDeclaration(functionDecl(
allOf(hasDeclContext(cxxRecordDecl(hasDeclContext(
namespaceDecl(hasName("::fbl"))))),
hasName("is_function")))))
.bind("expr"),
this);
Finder->addMatcher(
valueDecl(hasType(cxxRecordDecl(
allOf(hasDeclContext(namespaceDecl(hasName("::fbl"))),
hasName("is_function")))))
.bind("struct"),
this);
}
void FblTypeTraitsCheck::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<FblTypeTraitsPPCallbacks>(*this,
Compiler.getSourceManager()));
}
void FblTypeTraitsCheck::check(const MatchFinder::MatchResult &Result) {
SourceManager &SM = *Result.SourceManager;
SourceLocation Start;
SourceLocation End;
std::string Name;
if (const auto *V = Result.Nodes.getNodeAs<ValueDecl>("struct")) {
Start = V->getBeginLoc();
End = V->getEndLoc();
Name = V->getType().getTypePtr()->getAsCXXRecordDecl()->getNameAsString();
} else if (const auto *V = Result.Nodes.getNodeAs<CXXConstructExpr>("expr")) {
Start = V->getBeginLoc();
End = V->getEndLoc();
Name = V->getConstructor()->getNameAsString();
} else
return;
// 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 <type_traits> header, since we know this file uses it.
if (llvm::Optional<FixItHint> IncludeFixit =
Inserter->CreateIncludeInsertion(SM.getFileID(Start), "type_traits",
/*IsAngled=*/true)) {
Diag << *IncludeFixit;
}
} // namespace zircon
void FblTypeTraitsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IncludeStyle", IncludeStyle);
}
} // namespace zircon
} // namespace tidy
} // namespace clang