| //===--- 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 |