1 //===----------------------------------------------------------------------===//
2 //
3 // Copyright (c) 2012, 2013, 2015, 2016, 2019 The University of Utah
4 // Copyright (c) 2012 Konstantin Tokarev <annulen@yandex.ru>
5 // All rights reserved.
6 //
7 // This file is distributed under the University of Illinois Open Source
8 // License. See the file COPYING for details.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #if HAVE_CONFIG_H
13 # include <config.h>
14 #endif
15
16 #include "RemoveUnusedEnumMember.h"
17
18 #include <cctype>
19 #include "clang/AST/RecursiveASTVisitor.h"
20 #include "clang/AST/ASTContext.h"
21 #include "clang/Lex/Lexer.h"
22 #include "clang/Basic/SourceManager.h"
23
24 #include "TransformationManager.h"
25
26 using namespace clang;
27
28 static const char *DescriptionMsg =
29 "Remove unused enum member declarations. \n";
30
31 static RegisterTransformation<RemoveUnusedEnumMember>
32 Trans("remove-unused-enum-member", DescriptionMsg);
33
34 class RemoveUnusedEnumMemberAnalysisVisitor : public
35 RecursiveASTVisitor<RemoveUnusedEnumMemberAnalysisVisitor> {
36 public:
37
RemoveUnusedEnumMemberAnalysisVisitor(RemoveUnusedEnumMember * Instance)38 explicit RemoveUnusedEnumMemberAnalysisVisitor(
39 RemoveUnusedEnumMember *Instance)
40 : ConsumerInstance(Instance)
41 { }
42
43 bool VisitEnumDecl(EnumDecl *ED);
44
45 private:
46
47 RemoveUnusedEnumMember *ConsumerInstance;
48 };
49
VisitEnumDecl(EnumDecl * ED)50 bool RemoveUnusedEnumMemberAnalysisVisitor::VisitEnumDecl(EnumDecl *ED)
51 {
52 if (ConsumerInstance->isInIncludedFile(ED) || ED != ED->getCanonicalDecl())
53 return true;
54
55 for (EnumDecl::enumerator_iterator I = ED->enumerator_begin(),
56 E = ED->enumerator_end(); I != E; ++I) {
57 if (!(*I)->isReferenced()) {
58 ConsumerInstance->ValidInstanceNum++;
59 if (ConsumerInstance->ValidInstanceNum ==
60 ConsumerInstance->TransformationCounter) {
61 ConsumerInstance->TheEnumIterator = I;
62 ConsumerInstance->TheEnumDecl = ED;
63 }
64 }
65 }
66 return true;
67 }
68
Initialize(ASTContext & context)69 void RemoveUnusedEnumMember::Initialize(ASTContext &context)
70 {
71 Transformation::Initialize(context);
72 AnalysisVisitor = new RemoveUnusedEnumMemberAnalysisVisitor(this);
73 }
74
HandleTranslationUnit(ASTContext & Ctx)75 void RemoveUnusedEnumMember::HandleTranslationUnit(ASTContext &Ctx)
76 {
77 AnalysisVisitor->TraverseDecl(Ctx.getTranslationUnitDecl());
78
79 if (QueryInstanceOnly)
80 return;
81
82 if (TransformationCounter > ValidInstanceNum) {
83 TransError = TransMaxInstanceError;
84 return;
85 }
86
87 Ctx.getDiagnostics().setSuppressAllDiagnostics(false);
88
89 TransAssert(TheEnumDecl && "NULL TheEnumDecl!");
90
91 removeEnumConstantDecl();
92
93 if (Ctx.getDiagnostics().hasErrorOccurred() ||
94 Ctx.getDiagnostics().hasFatalErrorOccurred())
95 TransError = TransInternalError;
96 }
97
removeEnumConstantDecl()98 void RemoveUnusedEnumMember::removeEnumConstantDecl()
99 {
100 SourceLocation StartLoc = (*TheEnumIterator)->getBeginLoc();
101 if (StartLoc.isMacroID()) {
102 CharSourceRange Range = SrcManager->getExpansionRange(StartLoc);
103 StartLoc = Range.getBegin();
104 }
105 SourceLocation EndLoc = (*TheEnumIterator)->getEndLoc();
106 if (EndLoc.isMacroID()) {
107 CharSourceRange Range = SrcManager->getExpansionRange(EndLoc);
108 EndLoc = Range.getEnd();
109 }
110 SourceLocation CommaLoc = Lexer::findLocationAfterToken(
111 EndLoc, tok::comma, *SrcManager, Context->getLangOpts(),
112 /*SkipTrailingWhitespaceAndNewLine=*/false);
113 if (CommaLoc.isValid())
114 EndLoc = CommaLoc;
115 TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc));
116 }
117
~RemoveUnusedEnumMember()118 RemoveUnusedEnumMember::~RemoveUnusedEnumMember()
119 {
120 delete AnalysisVisitor;
121 }
122
123