blob: 4e70754d53b0f3a7b424b7d3a0bd1f9f7da45c98 [file] [log] [blame]
Samuel Benzaquen59c8aa92015-02-11 21:21:05 +00001//===--- GlobalNamesInHeadersCheck.cpp - clang-tidy -----------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "GlobalNamesInHeadersCheck.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/ASTMatchers/ASTMatchers.h"
14#include "clang/Lex/Lexer.h"
15
16using namespace clang::ast_matchers;
17
18namespace clang {
19namespace tidy {
Alexander Kornienkoed824e02015-03-05 13:46:14 +000020namespace google {
Samuel Benzaquen59c8aa92015-02-11 21:21:05 +000021namespace readability {
22
Haojian Wuc2d75772016-02-05 11:23:59 +000023GlobalNamesInHeadersCheck::GlobalNamesInHeadersCheck(StringRef Name,
24 ClangTidyContext *Context)
25 : ClangTidyCheck(Name, Context),
26 RawStringHeaderFileExtensions(
27 Options.getLocalOrGlobal("HeaderFileExtensions", "h")) {
28 if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions,
29 HeaderFileExtensions,
30 ',')) {
31 llvm::errs() << "Invalid header file extension: "
32 << RawStringHeaderFileExtensions << "\n";
33 }
34}
35
36void GlobalNamesInHeadersCheck::storeOptions(
37 ClangTidyOptions::OptionMap &Opts) {
38 Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions);
39}
40
Samuel Benzaquen59c8aa92015-02-11 21:21:05 +000041void
42GlobalNamesInHeadersCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
43 Finder->addMatcher(
44 decl(anyOf(usingDecl(), usingDirectiveDecl()),
45 hasDeclContext(translationUnitDecl())).bind("using_decl"),
46 this);
47}
48
49void GlobalNamesInHeadersCheck::check(const MatchFinder::MatchResult &Result) {
50 const auto *D = Result.Nodes.getNodeAs<Decl>("using_decl");
51 // If it comes from a macro, we'll assume it is fine.
52 if (D->getLocStart().isMacroID())
53 return;
54
55 // Ignore if it comes from the "main" file ...
56 if (Result.SourceManager->isInMainFile(
57 Result.SourceManager->getExpansionLoc(D->getLocStart()))) {
58 // unless that file is a header.
Haojian Wuc2d75772016-02-05 11:23:59 +000059 if (!utils::isSpellingLocInHeaderFile(
60 D->getLocStart(), *Result.SourceManager, HeaderFileExtensions))
Samuel Benzaquen59c8aa92015-02-11 21:21:05 +000061 return;
62 }
63
Samuel Benzaquen3199b9a2015-03-24 15:21:45 +000064 if (const auto* UsingDirective = dyn_cast<UsingDirectiveDecl>(D)) {
65 if (UsingDirective->getNominatedNamespace()->isAnonymousNamespace()) {
66 // Anynoumous namespaces inject a using directive into the AST to import
67 // the names into the containing namespace.
68 // We should not have them in headers, but there is another warning for
69 // that.
70 return;
71 }
72 }
73
Samuel Benzaquen59c8aa92015-02-11 21:21:05 +000074 diag(D->getLocStart(),
75 "using declarations in the global namespace in headers are prohibited");
76}
77
78} // namespace readability
Alexander Kornienkoed824e02015-03-05 13:46:14 +000079} // namespace google
Samuel Benzaquen59c8aa92015-02-11 21:21:05 +000080} // namespace tidy
81} // namespace clang