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