diff options
Diffstat (limited to 'Utilities/ClangTidyModule')
-rw-r--r-- | Utilities/ClangTidyModule/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Utilities/ClangTidyModule/Module.cxx | 3 | ||||
-rw-r--r-- | Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx | 101 | ||||
-rw-r--r-- | Utilities/ClangTidyModule/UseCmsysFstreamCheck.h | 24 |
4 files changed, 130 insertions, 0 deletions
diff --git a/Utilities/ClangTidyModule/CMakeLists.txt b/Utilities/ClangTidyModule/CMakeLists.txt index 6be13d6..51603aa 100644 --- a/Utilities/ClangTidyModule/CMakeLists.txt +++ b/Utilities/ClangTidyModule/CMakeLists.txt @@ -16,6 +16,8 @@ add_library(cmake-clang-tidy-module MODULE UseCmstrlenCheck.cxx UseCmstrlenCheck.h + UseCmsysFstreamCheck.cxx + UseCmsysFstreamCheck.h ) target_include_directories(cmake-clang-tidy-module PRIVATE ${CLANG_INCLUDE_DIRS}) target_link_libraries(cmake-clang-tidy-module PRIVATE clang-tidy) diff --git a/Utilities/ClangTidyModule/Module.cxx b/Utilities/ClangTidyModule/Module.cxx index a35c336..a9d344f 100644 --- a/Utilities/ClangTidyModule/Module.cxx +++ b/Utilities/ClangTidyModule/Module.cxx @@ -4,6 +4,7 @@ #include <clang-tidy/ClangTidyModuleRegistry.h> #include "UseCmstrlenCheck.h" +#include "UseCmsysFstreamCheck.h" namespace clang { namespace tidy { @@ -14,6 +15,8 @@ public: void addCheckFactories(ClangTidyCheckFactories& CheckFactories) override { CheckFactories.registerCheck<UseCmstrlenCheck>("cmake-use-cmstrlen"); + CheckFactories.registerCheck<UseCmsysFstreamCheck>( + "cmake-use-cmsys-fstream"); } }; diff --git a/Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx new file mode 100644 index 0000000..95a0a4d --- /dev/null +++ b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx @@ -0,0 +1,101 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "UseCmsysFstreamCheck.h" + +#include <clang/ASTMatchers/ASTMatchFinder.h> + +namespace clang { +namespace tidy { +namespace cmake { +using namespace ast_matchers; + +UseCmsysFstreamCheck::UseCmsysFstreamCheck(StringRef Name, + ClangTidyContext* Context) + : ClangTidyCheck(Name, Context) +{ +} + +void UseCmsysFstreamCheck::registerMatchers(MatchFinder* Finder) +{ + this->createMatcher("::std::basic_ifstream", "::cmsys::ifstream", Finder, + "ifstream"); + this->createMatcher("::std::basic_ofstream", "::cmsys::ofstream", Finder, + "ofstream"); + this->createMatcher("::std::basic_fstream", "::cmsys::fstream", Finder, + "fstream"); +} + +void UseCmsysFstreamCheck::check(const MatchFinder::MatchResult& Result) +{ + const TypeLoc* ParentTypeNode = + Result.Nodes.getNodeAs<TypeLoc>("parentType"); + const NestedNameSpecifierLoc* ParentNameNode = + Result.Nodes.getNodeAs<NestedNameSpecifierLoc>("parentName"); + const TypeLoc* RootNode = nullptr; + StringRef BindName; + StringRef Warning; + + if ((RootNode = Result.Nodes.getNodeAs<TypeLoc>("ifstream")) != nullptr) { + BindName = "cmsys::ifstream"; + Warning = "use cmsys::ifstream"; + } else if ((RootNode = Result.Nodes.getNodeAs<TypeLoc>("ofstream")) != + nullptr) { + BindName = "cmsys::ofstream"; + Warning = "use cmsys::ofstream"; + } else if ((RootNode = Result.Nodes.getNodeAs<TypeLoc>("fstream")) != + nullptr) { + BindName = "cmsys::fstream"; + Warning = "use cmsys::fstream"; + } + + if (ParentTypeNode != nullptr) { + if (ParentTypeNode->getBeginLoc().isValid()) { + this->diag(ParentTypeNode->getBeginLoc(), Warning) + << FixItHint::CreateReplacement(ParentTypeNode->getSourceRange(), + BindName); + } + } else if (ParentNameNode != nullptr) { + if (ParentNameNode->getBeginLoc().isValid()) { + this->diag(ParentNameNode->getBeginLoc(), Warning) + << FixItHint::CreateReplacement( + SourceRange(ParentNameNode->getBeginLoc(), RootNode->getEndLoc()), + BindName); + } + } else if (RootNode != nullptr) { + if (RootNode->getBeginLoc().isValid()) { + this->diag(RootNode->getBeginLoc(), Warning) + << FixItHint::CreateReplacement(RootNode->getSourceRange(), BindName); + } + } +} + +void UseCmsysFstreamCheck::createMatcher(StringRef StdName, + StringRef CmsysName, + ast_matchers::MatchFinder* Finder, + StringRef Bind) +{ + TypeLocMatcher IsStd = loc(qualType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(classTemplateSpecializationDecl( + hasName(StdName), + hasTemplateArgument( + 0, templateArgument(refersToType(asString("char")))))))))); + + // TODO This only checks to see if the type directly refers to + // cmsys::fstream. There are some corner cases involving template parameters + // that refer to cmsys::fstream that are missed by this matcher, resulting in + // a false positive. Figure out how to find these indirect references to + // cmsys::fstream and filter them out. In the meantime, such false positives + // can be silenced with NOLINT(cmake-use-cmsys-fstream). + TypeLocMatcher IsCmsys = + loc(usingType(throughUsingDecl(namedDecl(hasName(CmsysName))))); + + Finder->addMatcher( + typeLoc(IsStd, unless(IsCmsys), unless(elaboratedTypeLoc()), + optionally(hasParent(elaboratedTypeLoc().bind("parentType"))), + optionally(hasParent(nestedNameSpecifierLoc().bind("parentName")))) + .bind(Bind), + this); +} +} +} +} diff --git a/Utilities/ClangTidyModule/UseCmsysFstreamCheck.h b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.h new file mode 100644 index 0000000..782123c --- /dev/null +++ b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.h @@ -0,0 +1,24 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <clang-tidy/ClangTidyCheck.h> +#include <clang/ASTMatchers/ASTMatchFinder.h> + +namespace clang { +namespace tidy { +namespace cmake { +class UseCmsysFstreamCheck : public ClangTidyCheck +{ +public: + UseCmsysFstreamCheck(StringRef Name, ClangTidyContext* Context); + void registerMatchers(ast_matchers::MatchFinder* Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult& Result) override; + +private: + void createMatcher(StringRef name, StringRef CmsysName, + ast_matchers::MatchFinder* Finder, StringRef bind); +}; +} +} +} |