Mercurial > hg > CbC > CbC_llvm
view clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.cpp @ 252:1f2b6ac9f198 llvm-original
LLVM16-1
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 18 Aug 2023 09:04:13 +0900 |
parents | c4bab56944e8 |
children |
line wrap: on
line source
//===--- DeprecatedHeadersCheck.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 "DeprecatedHeadersCheck.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" #include <algorithm> #include <vector> using IncludeMarker = clang::tidy::modernize::DeprecatedHeadersCheck::IncludeMarker; namespace clang::tidy::modernize { namespace { class IncludeModernizePPCallbacks : public PPCallbacks { public: explicit IncludeModernizePPCallbacks( std::vector<IncludeMarker> &IncludesToBeProcessed, LangOptions LangOpts, const SourceManager &SM, bool CheckHeaderFile); void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, StringRef SearchPath, StringRef RelativePath, const Module *Imported, SrcMgr::CharacteristicKind FileType) override; private: std::vector<IncludeMarker> &IncludesToBeProcessed; LangOptions LangOpts; llvm::StringMap<std::string> CStyledHeaderToCxx; llvm::StringSet<> DeleteHeaders; const SourceManager &SM; bool CheckHeaderFile; }; class ExternCRefutationVisitor : public RecursiveASTVisitor<ExternCRefutationVisitor> { std::vector<IncludeMarker> &IncludesToBeProcessed; const SourceManager &SM; public: ExternCRefutationVisitor(std::vector<IncludeMarker> &IncludesToBeProcessed, SourceManager &SM) : IncludesToBeProcessed(IncludesToBeProcessed), SM(SM) {} bool shouldWalkTypesOfTypeLocs() const { return false; } bool shouldVisitLambdaBody() const { return false; } bool VisitLinkageSpecDecl(LinkageSpecDecl *LinkSpecDecl) const { if (LinkSpecDecl->getLanguage() != LinkageSpecDecl::lang_c || !LinkSpecDecl->hasBraces()) return true; auto ExternCBlockBegin = LinkSpecDecl->getBeginLoc(); auto ExternCBlockEnd = LinkSpecDecl->getEndLoc(); auto IsWrapped = [=, &SM = SM](const IncludeMarker &Marker) -> bool { return SM.isBeforeInTranslationUnit(ExternCBlockBegin, Marker.DiagLoc) && SM.isBeforeInTranslationUnit(Marker.DiagLoc, ExternCBlockEnd); }; llvm::erase_if(IncludesToBeProcessed, IsWrapped); return true; } }; } // namespace DeprecatedHeadersCheck::DeprecatedHeadersCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), CheckHeaderFile(Options.get("CheckHeaderFile", false)) {} void DeprecatedHeadersCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "CheckHeaderFile", CheckHeaderFile); } void DeprecatedHeadersCheck::registerPPCallbacks( const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { PP->addPPCallbacks(std::make_unique<IncludeModernizePPCallbacks>( IncludesToBeProcessed, getLangOpts(), PP->getSourceManager(), CheckHeaderFile)); } void DeprecatedHeadersCheck::registerMatchers( ast_matchers::MatchFinder *Finder) { // Even though the checker operates on a "preprocessor" level, we still need // to act on a "TranslationUnit" to acquire the AST where we can walk each // Decl and look for `extern "C"` blocks where we will suppress the report we // collected during the preprocessing phase. // The `onStartOfTranslationUnit()` won't suffice, since we need some handle // to the `ASTContext`. Finder->addMatcher(ast_matchers::translationUnitDecl().bind("TU"), this); } void DeprecatedHeadersCheck::onEndOfTranslationUnit() { IncludesToBeProcessed.clear(); } void DeprecatedHeadersCheck::check( const ast_matchers::MatchFinder::MatchResult &Result) { SourceManager &SM = Result.Context->getSourceManager(); // Suppress includes wrapped by `extern "C" { ... }` blocks. ExternCRefutationVisitor Visitor(IncludesToBeProcessed, SM); Visitor.TraverseAST(*Result.Context); // Emit all the remaining reports. for (const IncludeMarker &Marker : IncludesToBeProcessed) { if (Marker.Replacement.empty()) { diag(Marker.DiagLoc, "including '%0' has no effect in C++; consider removing it") << Marker.FileName << FixItHint::CreateRemoval(Marker.ReplacementRange); } else { diag(Marker.DiagLoc, "inclusion of deprecated C++ header " "'%0'; consider using '%1' instead") << Marker.FileName << Marker.Replacement << FixItHint::CreateReplacement( Marker.ReplacementRange, (llvm::Twine("<") + Marker.Replacement + ">").str()); } } } IncludeModernizePPCallbacks::IncludeModernizePPCallbacks( std::vector<IncludeMarker> &IncludesToBeProcessed, LangOptions LangOpts, const SourceManager &SM, bool CheckHeaderFile) : IncludesToBeProcessed(IncludesToBeProcessed), LangOpts(LangOpts), SM(SM), CheckHeaderFile(CheckHeaderFile) { for (const auto &KeyValue : std::vector<std::pair<llvm::StringRef, std::string>>( {{"assert.h", "cassert"}, {"complex.h", "complex"}, {"ctype.h", "cctype"}, {"errno.h", "cerrno"}, {"float.h", "cfloat"}, {"limits.h", "climits"}, {"locale.h", "clocale"}, {"math.h", "cmath"}, {"setjmp.h", "csetjmp"}, {"signal.h", "csignal"}, {"stdarg.h", "cstdarg"}, {"stddef.h", "cstddef"}, {"stdio.h", "cstdio"}, {"stdlib.h", "cstdlib"}, {"string.h", "cstring"}, {"time.h", "ctime"}, {"wchar.h", "cwchar"}, {"wctype.h", "cwctype"}})) { CStyledHeaderToCxx.insert(KeyValue); } // Add C++ 11 headers. if (LangOpts.CPlusPlus11) { for (const auto &KeyValue : std::vector<std::pair<llvm::StringRef, std::string>>( {{"fenv.h", "cfenv"}, {"stdint.h", "cstdint"}, {"inttypes.h", "cinttypes"}, {"tgmath.h", "ctgmath"}, {"uchar.h", "cuchar"}})) { CStyledHeaderToCxx.insert(KeyValue); } } for (const auto &Key : std::vector<std::string>({"stdalign.h", "stdbool.h", "iso646.h"})) { DeleteHeaders.insert(Key); } } void IncludeModernizePPCallbacks::InclusionDirective( SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, StringRef SearchPath, StringRef RelativePath, const Module *Imported, SrcMgr::CharacteristicKind FileType) { // If we don't want to warn for non-main file reports and this is one, skip // it. if (!CheckHeaderFile && !SM.isInMainFile(HashLoc)) return; // Ignore system headers. if (SM.isInSystemHeader(HashLoc)) return; // FIXME: Take care of library symbols from the global namespace. // // Reasonable options for the check: // // 1. Insert std prefix for every such symbol occurrence. // 2. Insert `using namespace std;` to the beginning of TU. // 3. Do nothing and let the user deal with the migration himself. SourceLocation DiagLoc = FilenameRange.getBegin(); if (CStyledHeaderToCxx.count(FileName) != 0) { IncludesToBeProcessed.push_back( IncludeMarker{CStyledHeaderToCxx[FileName], FileName, FilenameRange.getAsRange(), DiagLoc}); } else if (DeleteHeaders.count(FileName) != 0) { IncludesToBeProcessed.push_back( IncludeMarker{std::string{}, FileName, SourceRange{HashLoc, FilenameRange.getEnd()}, DiagLoc}); } } } // namespace clang::tidy::modernize