summaryrefslogtreecommitdiff
path: root/Utilities/ClangTidyModule
diff options
context:
space:
mode:
authorJoe Blaauboer <jblaauboer67@gmail.com>2022-10-24 13:24:57 -0400
committerKyle Edwards <kyle.edwards@kitware.com>2022-11-04 11:33:23 -0400
commitd5208536824fb2c9ad3466b0ca140ea3d3d0ed2b (patch)
treed817b6c8061d1cad1ffc76531fb1a62ff5ffdb29 /Utilities/ClangTidyModule
parentc67b91a7a6472f23ce8d51c4bbf5e338418cc0a3 (diff)
downloadcmake-d5208536824fb2c9ad3466b0ca140ea3d3d0ed2b.tar.gz
clang-tidy module: add check for cmsys::fstream
Co-Authored-by: Kyle Edwards <kyle.edwards@kitware.com> Co-Authored-by: Igor-Mikhail-Valentin Glebov <iglebov@albany.edu>
Diffstat (limited to 'Utilities/ClangTidyModule')
-rw-r--r--Utilities/ClangTidyModule/CMakeLists.txt2
-rw-r--r--Utilities/ClangTidyModule/Module.cxx3
-rw-r--r--Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx101
-rw-r--r--Utilities/ClangTidyModule/UseCmsysFstreamCheck.h24
4 files changed, 130 insertions, 0 deletions
diff --git a/Utilities/ClangTidyModule/CMakeLists.txt b/Utilities/ClangTidyModule/CMakeLists.txt
index 6be13d608d..51603aa32a 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 a35c3367a3..a9d344ff4a 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 0000000000..95a0a4d6fa
--- /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 0000000000..782123c12a
--- /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);
+};
+}
+}
+}