[clang-tools-extra] create new clang-tidy check to add namespaces to symbol references (PR #70621)

Piotr Zegar via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 30 08:45:46 PDT 2023


================
@@ -0,0 +1,840 @@
+//===--- UseExplicitNamespacesCheck.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 "UseExplicitNamespacesCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/TokenKinds.h"
+#include "clang/Lex/Lexer.h"
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+bool isTransparentNamespace(const NamespaceDecl *decl) {
+  return decl->isInline() || decl->isAnonymousNamespace();
+}
+
+std::string getIdentifierString(const IdentifierInfo *identifier) {
+  return (identifier) ? identifier->getNameStart() : "(nullptr)";
+}
+
+std::string getMatchContext(const char *match, const DynTypedNode &node) {
+  std::stringstream out;
+  out << match << "(" << node.getNodeKind().asStringRef().str() << ")";
+  return out.str();
+}
+
+std::string trueFalseString(bool value) { return value ? "true" : "false"; }
+
+UseExplicitNamespacesCheck::UseExplicitNamespacesCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      limitToPattern(Options.get("LimitToPattern", "")),
+      onlyExpandUsingNamespace(Options.get("OnlyExpandUsingNamespace", true)),
+      diagnosticLevel(Options.get("DiagnosticLevel", 0)) {
+  auto limitString = limitToPattern.str();
+  size_t startIndex = 0;
+  while (startIndex < limitString.size()) {
+    size_t found = limitString.find("::", startIndex);
+    size_t end = found == std::string::npos ? limitString.size() : found;
+    size_t length = end - startIndex;
+    if (length) {
+      limitToPatternVector.emplace_back(limitString, startIndex, length);
+    }
+    startIndex = end + 2;
+  }
+}
+
+void UseExplicitNamespacesCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "LimitToPattern", limitToPattern);
+  Options.store(Opts, "OnlyExpandUsingNamespace", onlyExpandUsingNamespace);
+  Options.store(Opts, "DiagnosticLevel", diagnosticLevel);
+}
+
+void UseExplicitNamespacesCheck::registerMatchers(
+    ast_matchers::MatchFinder *Finder) {
+  Finder->addMatcher(
+      declRefExpr(unless(hasAncestor(substNonTypeTemplateParmExpr())))
+          .bind("DeclRefExpr"),
+      this);
+  Finder->addMatcher(declaratorDecl().bind("DeclaratorDecl"), this);
+  Finder->addMatcher(cxxNewExpr().bind("CXXNewExpr"), this);
+  Finder->addMatcher(cxxTemporaryObjectExpr().bind("CXXTemporaryObjectExpr"),
+                     this);
+  Finder->addMatcher(typedefNameDecl().bind("TypedefNameDecl"), this);
+}
+
+bool UseExplicitNamespacesCheck::matchesNamespaceLimits(
+    const std::vector<const DeclContext *> &targetContextVector) {
+  if (limitToPatternVector.empty()) {
+    return true;
+  }
+  size_t currentTargetIndex = 0;
+  auto findMatch = [&currentTargetIndex,
+                    &targetContextVector](const std::string &name) -> bool {
+    while (currentTargetIndex < targetContextVector.size()) {
+      auto currentContext = targetContextVector[currentTargetIndex];
+      ++currentTargetIndex;
+      if (auto currentNamespace = dyn_cast<NamespaceDecl>(currentContext)) {
+        if (currentNamespace->isAnonymousNamespace()) {
+          return false;
+        }
+        if (currentNamespace->getIdentifier()->getName().str() == name) {
+          return true;
+        }
+        if (!currentNamespace->isInline()) {
+          return false;
+        }
+      } else {
+        return false;
+      }
+    }
+    return false;
+  };
+  for (size_t i = 0; i < limitToPatternVector.size(); ++i) {
+    if (!findMatch(limitToPatternVector[i])) {
+      return false;
+    }
+  }
+  for (; currentTargetIndex < targetContextVector.size();
+       ++currentTargetIndex) {
+    auto currentContext = targetContextVector[currentTargetIndex];
+    if (auto currentNamespace = dyn_cast<NamespaceDecl>(currentContext)) {
+      if (!isTransparentNamespace(currentNamespace)) {
+        return false;
+      }
+    } else {
+      return true;
+    }
+  }
+  return true;
+}
+
+IdentifierInfo *UseExplicitNamespacesCheck::getTypeNestedNameIdentfierRecursive(
----------------
PiotrZSL wrote:

Not needed to make check working, remove custom diagnostic.

https://github.com/llvm/llvm-project/pull/70621


More information about the cfe-commits mailing list