Explorar o código

clang-tidy module: add check for cmsys::fstream

Co-Authored-by: Kyle Edwards <[email protected]>
Co-Authored-by: Igor-Mikhail-Valentin Glebov <[email protected]>
Joe Blaauboer %!s(int64=3) %!d(string=hai) anos
pai
achega
d520853682

+ 2 - 0
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)

+ 3 - 0
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");
   }
 };
 

+ 101 - 0
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);
+}
+}
+}
+}

+ 24 - 0
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);
+};
+}
+}
+}