clang-tools  10.0.0svn
UnusedUsingDeclsCheck.cpp
Go to the documentation of this file.
1 //===--- UnusedUsingDeclsCheck.cpp - clang-tidy----------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Lex/Lexer.h"
13 
14 using namespace clang::ast_matchers;
15 
16 namespace clang {
17 namespace tidy {
18 namespace misc {
19 
20 // A function that helps to tell whether a TargetDecl in a UsingDecl will be
21 // checked. Only variable, function, function template, class template, class,
22 // enum declaration and enum constant declaration are considered.
23 static bool ShouldCheckDecl(const Decl *TargetDecl) {
24  return isa<RecordDecl>(TargetDecl) || isa<ClassTemplateDecl>(TargetDecl) ||
25  isa<FunctionDecl>(TargetDecl) || isa<VarDecl>(TargetDecl) ||
26  isa<FunctionTemplateDecl>(TargetDecl) || isa<EnumDecl>(TargetDecl) ||
27  isa<EnumConstantDecl>(TargetDecl);
28 }
29 
30 void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *Finder) {
31  Finder->addMatcher(usingDecl(isExpansionInMainFile()).bind("using"), this);
32  auto DeclMatcher = hasDeclaration(namedDecl().bind("used"));
33  Finder->addMatcher(loc(enumType(DeclMatcher)), this);
34  Finder->addMatcher(loc(recordType(DeclMatcher)), this);
35  Finder->addMatcher(loc(templateSpecializationType(DeclMatcher)), this);
36  Finder->addMatcher(declRefExpr().bind("used"), this);
37  Finder->addMatcher(callExpr(callee(unresolvedLookupExpr().bind("used"))),
38  this);
39  Finder->addMatcher(
40  callExpr(hasDeclaration(functionDecl(hasAnyTemplateArgument(
41  anyOf(refersToTemplate(templateName().bind("used")),
42  refersToDeclaration(functionDecl().bind("used"))))))),
43  this);
44  Finder->addMatcher(loc(templateSpecializationType(hasAnyTemplateArgument(
45  templateArgument().bind("used")))),
46  this);
47 }
48 
49 void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) {
50  if (Result.Context->getDiagnostics().hasUncompilableErrorOccurred())
51  return;
52 
53  if (const auto *Using = Result.Nodes.getNodeAs<UsingDecl>("using")) {
54  // Ignores using-declarations defined in macros.
55  if (Using->getLocation().isMacroID())
56  return;
57 
58  // Ignores using-declarations defined in class definition.
59  if (isa<CXXRecordDecl>(Using->getDeclContext()))
60  return;
61 
62  // FIXME: We ignore using-decls defined in function definitions at the
63  // moment because of false positives caused by ADL and different function
64  // scopes.
65  if (isa<FunctionDecl>(Using->getDeclContext()))
66  return;
67 
68  UsingDeclContext Context(Using);
69  Context.UsingDeclRange = CharSourceRange::getCharRange(
70  Using->getBeginLoc(),
71  Lexer::findLocationAfterToken(
72  Using->getEndLoc(), tok::semi, *Result.SourceManager, getLangOpts(),
73  /*SkipTrailingWhitespaceAndNewLine=*/true));
74  for (const auto *UsingShadow : Using->shadows()) {
75  const auto *TargetDecl = UsingShadow->getTargetDecl()->getCanonicalDecl();
76  if (ShouldCheckDecl(TargetDecl))
77  Context.UsingTargetDecls.insert(TargetDecl);
78  }
79  if (!Context.UsingTargetDecls.empty())
80  Contexts.push_back(Context);
81  return;
82  }
83  // Mark using declarations as used by setting FoundDecls' value to zero. As
84  // the AST is walked in order, usages are only marked after a the
85  // corresponding using declaration has been found.
86  // FIXME: This currently doesn't look at whether the type reference is
87  // actually found with the help of the using declaration.
88  if (const auto *Used = Result.Nodes.getNodeAs<NamedDecl>("used")) {
89  if (const auto *FD = dyn_cast<FunctionDecl>(Used)) {
90  removeFromFoundDecls(FD->getPrimaryTemplate());
91  } else if (const auto *Specialization =
92  dyn_cast<ClassTemplateSpecializationDecl>(Used)) {
93  Used = Specialization->getSpecializedTemplate();
94  }
95  removeFromFoundDecls(Used);
96  return;
97  }
98 
99  if (const auto *Used = Result.Nodes.getNodeAs<TemplateArgument>("used")) {
100  // FIXME: Support non-type template parameters.
101  if (Used->getKind() == TemplateArgument::Template) {
102  if (const auto *TD = Used->getAsTemplate().getAsTemplateDecl())
103  removeFromFoundDecls(TD);
104  } else if (Used->getKind() == TemplateArgument::Type) {
105  if (auto *RD = Used->getAsType()->getAsCXXRecordDecl())
106  removeFromFoundDecls(RD);
107  }
108  return;
109  }
110 
111  if (const auto *Used = Result.Nodes.getNodeAs<TemplateName>("used")) {
112  removeFromFoundDecls(Used->getAsTemplateDecl());
113  return;
114  }
115 
116  if (const auto *DRE = Result.Nodes.getNodeAs<DeclRefExpr>("used")) {
117  if (const auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
118  if (const auto *FDT = FD->getPrimaryTemplate())
119  removeFromFoundDecls(FDT);
120  else
121  removeFromFoundDecls(FD);
122  } else if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
123  removeFromFoundDecls(VD);
124  } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
125  removeFromFoundDecls(ECD);
126  if (const auto *ET = ECD->getType()->getAs<EnumType>())
127  removeFromFoundDecls(ET->getDecl());
128  }
129  }
130  // Check the uninstantiated template function usage.
131  if (const auto *ULE = Result.Nodes.getNodeAs<UnresolvedLookupExpr>("used")) {
132  for (const NamedDecl *ND : ULE->decls()) {
133  if (const auto *USD = dyn_cast<UsingShadowDecl>(ND))
134  removeFromFoundDecls(USD->getTargetDecl()->getCanonicalDecl());
135  }
136  }
137 }
138 
139 void UnusedUsingDeclsCheck::removeFromFoundDecls(const Decl *D) {
140  if (!D)
141  return;
142  // FIXME: Currently, we don't handle the using-decls being used in different
143  // scopes (such as different namespaces, different functions). Instead of
144  // giving an incorrect message, we mark all of them as used.
145  //
146  // FIXME: Use a more efficient way to find a matching context.
147  for (auto &Context : Contexts) {
148  if (Context.UsingTargetDecls.count(D->getCanonicalDecl()) > 0)
149  Context.IsUsed = true;
150  }
151 }
152 
153 void UnusedUsingDeclsCheck::onEndOfTranslationUnit() {
154  for (const auto &Context : Contexts) {
155  if (!Context.IsUsed) {
156  diag(Context.FoundUsingDecl->getLocation(), "using decl %0 is unused")
157  << Context.FoundUsingDecl;
158  // Emit a fix and a fix description of the check;
159  diag(Context.FoundUsingDecl->getLocation(),
160  /*Description=*/"remove the using", DiagnosticIDs::Note)
161  << FixItHint::CreateRemoval(Context.UsingDeclRange);
162  }
163  }
164  Contexts.clear();
165 }
166 
167 } // namespace misc
168 } // namespace tidy
169 } // namespace clang
static bool ShouldCheckDecl(const Decl *TargetDecl)
const Decl * D
Definition: XRefs.cpp:873
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
NodeType Type