[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 = [¤tTargetIndex,
+ &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