summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/modernize
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy/modernize')
-rw-r--r--clang-tools-extra/clang-tidy/modernize/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.cpp113
-rw-r--r--clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.h41
-rw-r--r--clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp3
4 files changed, 158 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 907eb6c3046..06ea18d670a 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTidyModernizeModule
AvoidBindCheck.cpp
+ ConcatNestedNamespacesCheck.cpp
DeprecatedHeadersCheck.cpp
LoopConvertCheck.cpp
LoopConvertUtils.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.cpp
new file mode 100644
index 00000000000..bef85f7b357
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.cpp
@@ -0,0 +1,113 @@
+//===--- ConcatNestedNamespacesCheck.cpp - clang-tidy----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ConcatNestedNamespacesCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <algorithm>
+#include <iterator>
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+static bool locationsInSameFile(const SourceManager &Sources,
+ SourceLocation Loc1, SourceLocation Loc2) {
+ return Loc1.isFileID() && Loc2.isFileID() &&
+ Sources.getFileID(Loc1) == Sources.getFileID(Loc2);
+}
+
+static bool anonymousOrInlineNamespace(const NamespaceDecl &ND) {
+ return ND.isAnonymousNamespace() || ND.isInlineNamespace();
+}
+
+static bool singleNamedNamespaceChild(const NamespaceDecl &ND) {
+ NamespaceDecl::decl_range Decls = ND.decls();
+ if (std::distance(Decls.begin(), Decls.end()) != 1)
+ return false;
+
+ const auto *ChildNamespace = dyn_cast<const NamespaceDecl>(*Decls.begin());
+ return ChildNamespace && !anonymousOrInlineNamespace(*ChildNamespace);
+}
+
+static bool alreadyConcatenated(std::size_t NumCandidates,
+ const SourceRange &ReplacementRange,
+ const SourceManager &Sources,
+ const LangOptions &LangOpts) {
+ CharSourceRange TextRange =
+ Lexer::getAsCharRange(ReplacementRange, Sources, LangOpts);
+ StringRef CurrentNamespacesText =
+ Lexer::getSourceText(TextRange, Sources, LangOpts);
+ return CurrentNamespacesText.count(':') == (NumCandidates - 1) * 2;
+}
+
+ConcatNestedNamespacesCheck::NamespaceString
+ConcatNestedNamespacesCheck::concatNamespaces() {
+ NamespaceString Result("namespace ");
+ Result.append(Namespaces.front()->getName());
+
+ std::for_each(std::next(Namespaces.begin()), Namespaces.end(),
+ [&Result](const NamespaceDecl *ND) {
+ Result.append("::");
+ Result.append(ND->getName());
+ });
+
+ return Result;
+}
+
+void ConcatNestedNamespacesCheck::registerMatchers(
+ ast_matchers::MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus17)
+ return;
+
+ Finder->addMatcher(ast_matchers::namespaceDecl().bind("namespace"), this);
+}
+
+void ConcatNestedNamespacesCheck::reportDiagnostic(
+ const SourceRange &FrontReplacement, const SourceRange &BackReplacement) {
+ diag(Namespaces.front()->getBeginLoc(),
+ "nested namespaces can be concatenated", DiagnosticIDs::Warning)
+ << FixItHint::CreateReplacement(FrontReplacement, concatNamespaces())
+ << FixItHint::CreateReplacement(BackReplacement, "}");
+}
+
+void ConcatNestedNamespacesCheck::check(
+ const ast_matchers::MatchFinder::MatchResult &Result) {
+ const NamespaceDecl &ND = *Result.Nodes.getNodeAs<NamespaceDecl>("namespace");
+ const SourceManager &Sources = *Result.SourceManager;
+
+ if (!locationsInSameFile(Sources, ND.getBeginLoc(), ND.getRBraceLoc()))
+ return;
+
+ if (!Sources.isInMainFile(ND.getBeginLoc()))
+ return;
+
+ if (anonymousOrInlineNamespace(ND))
+ return;
+
+ Namespaces.push_back(&ND);
+
+ if (singleNamedNamespaceChild(ND))
+ return;
+
+ SourceRange FrontReplacement(Namespaces.front()->getBeginLoc(),
+ Namespaces.back()->getLocation());
+ SourceRange BackReplacement(Namespaces.back()->getRBraceLoc(),
+ Namespaces.front()->getRBraceLoc());
+
+ if (!alreadyConcatenated(Namespaces.size(), FrontReplacement, Sources,
+ getLangOpts()))
+ reportDiagnostic(FrontReplacement, BackReplacement);
+
+ Namespaces.clear();
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.h b/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.h
new file mode 100644
index 00000000000..547690d2e87
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.h
@@ -0,0 +1,41 @@
+//===--- ConcatNestedNamespacesCheck.h - clang-tidy--------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_CONCATNESTEDNAMESPACESCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_CONCATNESTEDNAMESPACESCHECK_H
+
+#include "../ClangTidy.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+class ConcatNestedNamespacesCheck : public ClangTidyCheck {
+public:
+ ConcatNestedNamespacesCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ using NamespaceContextVec = llvm::SmallVector<const NamespaceDecl *, 6>;
+ using NamespaceString = llvm::SmallString<40>;
+
+ void reportDiagnostic(const SourceRange &FrontReplacement,
+ const SourceRange &BackReplacement);
+ NamespaceString concatNamespaces();
+ NamespaceContextVec Namespaces;
+};
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_CONCATNESTEDNAMESPACESCHECK_H
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 63b7d022609..fa0a4907129 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -11,6 +11,7 @@
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
#include "AvoidBindCheck.h"
+#include "ConcatNestedNamespacesCheck.h"
#include "DeprecatedHeadersCheck.h"
#include "LoopConvertCheck.h"
#include "MakeSharedCheck.h"
@@ -46,6 +47,8 @@ class ModernizeModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
CheckFactories.registerCheck<AvoidBindCheck>("modernize-avoid-bind");
+ CheckFactories.registerCheck<ConcatNestedNamespacesCheck>(
+ "modernize-concat-nested-namespaces");
CheckFactories.registerCheck<DeprecatedHeadersCheck>(
"modernize-deprecated-headers");
CheckFactories.registerCheck<LoopConvertCheck>("modernize-loop-convert");
OpenPOWER on IntegriCloud