forked from llvm/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathClangExtDefMapGen.cpp
226 lines (188 loc) · 7.07 KB
/
ClangExtDefMapGen.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
//===- ClangExtDefMapGen.cpp ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===--------------------------------------------------------------------===//
//
// Clang tool which creates a list of defined functions and the files in which
// they are defined.
//
//===--------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/CrossTU/CrossTranslationUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h"
#include <optional>
#include <sstream>
#include <string>
using namespace llvm;
using namespace clang;
using namespace clang::cross_tu;
using namespace clang::tooling;
static cl::OptionCategory
ClangExtDefMapGenCategory("clang-extdefmapgen options");
class MapExtDefNamesConsumer : public ASTConsumer {
public:
MapExtDefNamesConsumer(ASTContext &Context,
StringRef astFilePath = StringRef())
: Ctx(Context), SM(Context.getSourceManager()) {
CurrentFileName = astFilePath.str();
}
~MapExtDefNamesConsumer() {
// Flush results to standard output.
llvm::outs() << createCrossTUIndexString(Index);
}
void HandleTranslationUnit(ASTContext &Context) override {
handleDecl(Context.getTranslationUnitDecl());
}
private:
void handleDecl(const Decl *D);
void addIfInMain(const DeclaratorDecl *DD, SourceLocation defStart);
ASTContext &Ctx;
SourceManager &SM;
llvm::StringMap<std::string> Index;
std::string CurrentFileName;
};
void MapExtDefNamesConsumer::handleDecl(const Decl *D) {
if (!D)
return;
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isThisDeclarationADefinition())
if (const Stmt *Body = FD->getBody())
addIfInMain(FD, Body->getBeginLoc());
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (cross_tu::shouldImport(VD, Ctx) && VD->hasInit())
if (const Expr *Init = VD->getInit())
addIfInMain(VD, Init->getBeginLoc());
}
if (const auto *DC = dyn_cast<DeclContext>(D))
for (const Decl *D : DC->decls())
handleDecl(D);
}
void MapExtDefNamesConsumer::addIfInMain(const DeclaratorDecl *DD,
SourceLocation defStart) {
std::optional<std::string> LookupName =
CrossTranslationUnitContext::getLookupName(DD);
if (!LookupName)
return;
assert(!LookupName->empty() && "Lookup name should be non-empty.");
if (CurrentFileName.empty()) {
CurrentFileName = std::string(
SM.getFileEntryForID(SM.getMainFileID())->tryGetRealPathName());
if (CurrentFileName.empty())
CurrentFileName = "invalid_file";
}
switch (DD->getLinkageInternal()) {
case Linkage::External:
case Linkage::VisibleNone:
case Linkage::UniqueExternal:
if (SM.isInMainFile(defStart))
Index[*LookupName] = CurrentFileName;
break;
case Linkage::Invalid:
llvm_unreachable("Linkage has not been computed!");
default:
break;
}
}
class MapExtDefNamesAction : public ASTFrontendAction {
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef) override {
return std::make_unique<MapExtDefNamesConsumer>(CI.getASTContext());
}
};
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
IntrusiveRefCntPtr<DiagnosticsEngine> GetDiagnosticsEngine() {
if (Diags) {
// Call reset to make sure we don't mix errors
Diags->Reset(false);
return Diags;
}
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticPrinter *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
DiagClient->setPrefix("clang-extdef-mappping");
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine(
new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
Diags.swap(DiagEngine);
// Retain this one time so it's not destroyed by ASTUnit::LoadFromASTFile
Diags->Retain();
return Diags;
}
static CompilerInstance *CI = nullptr;
static bool HandleAST(StringRef AstPath) {
if (!CI)
CI = new CompilerInstance();
IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine = GetDiagnosticsEngine();
std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
AstPath.str(), CI->getPCHContainerOperations()->getRawReader(),
ASTUnit::LoadASTOnly, DiagEngine, CI->getFileSystemOpts(),
CI->getHeaderSearchOptsPtr());
if (!Unit)
return false;
FileManager FM(CI->getFileSystemOpts());
SmallString<128> AbsPath(AstPath);
FM.makeAbsolutePath(AbsPath);
MapExtDefNamesConsumer Consumer =
MapExtDefNamesConsumer(Unit->getASTContext(), AbsPath);
Consumer.HandleTranslationUnit(Unit->getASTContext());
return true;
}
static int HandleFiles(ArrayRef<std::string> SourceFiles,
CompilationDatabase &compilations) {
std::vector<std::string> SourcesToBeParsed;
// Loop over all input files, if they are pre-compiled AST
// process them directly in HandleAST, otherwise put them
// on a list for ClangTool to handle.
for (StringRef Src : SourceFiles) {
if (Src.ends_with(".ast")) {
if (!HandleAST(Src)) {
return 1;
}
} else {
SourcesToBeParsed.push_back(Src.str());
}
}
if (!SourcesToBeParsed.empty()) {
ClangTool Tool(compilations, SourcesToBeParsed);
return Tool.run(newFrontendActionFactory<MapExtDefNamesAction>().get());
}
return 0;
}
int main(int argc, const char **argv) {
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal(argv[0], false);
PrettyStackTraceProgram X(argc, argv);
const char *Overview = "\nThis tool collects the USR name and location "
"of external definitions in the source files "
"(excluding headers).\n"
"Input can be either source files that are compiled "
"with compile database or .ast files that are "
"created from clang's -emit-ast option.\n";
auto ExpectedParser = CommonOptionsParser::create(
argc, argv, ClangExtDefMapGenCategory, cl::ZeroOrMore, Overview);
if (!ExpectedParser) {
llvm::errs() << ExpectedParser.takeError();
return 1;
}
CommonOptionsParser &OptionsParser = ExpectedParser.get();
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
return HandleFiles(OptionsParser.getSourcePathList(),
OptionsParser.getCompilations());
}