1 //===--- index-test.cpp - Indexing test bed -------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This utility may be invoked in the following manner:
11 // index-test --help - Output help info.
12 // index-test [options] - Read from stdin.
13 // index-test [options] file - Read from "file".
14 // index-test [options] file1 file2 - Read these files.
16 // Files must be AST files.
18 //===----------------------------------------------------------------------===//
20 // -point-at [file:column:line]
21 // Point at a declaration/statement/expression. If no other operation is
22 // specified, prints some info about it.
25 // Print ASTLocations that reference the -point-at node
28 // Print ASTLocations that define the -point-at node
31 // Print ASTLocations that declare the -point-at node
33 //===----------------------------------------------------------------------===//
35 #include "clang/Index/Program.h"
36 #include "clang/Index/IndexProvider.h"
37 #include "clang/Index/Entity.h"
38 #include "clang/Index/TranslationUnit.h"
39 #include "clang/Index/ASTLocation.h"
40 #include "clang/Index/DeclReferenceMap.h"
41 #include "clang/Index/Utils.h"
42 #include "clang/Frontend/ASTUnit.h"
43 #include "clang/Frontend/CommandLineSourceLoc.h"
44 #include "clang/AST/Decl.h"
45 #include "clang/AST/Expr.h"
46 #include "clang/Basic/FileManager.h"
47 #include "clang/Basic/SourceManager.h"
48 #include "llvm/Support/CommandLine.h"
49 #include "llvm/Support/ManagedStatic.h"
50 #include "llvm/Support/PrettyStackTrace.h"
51 #include "llvm/Support/raw_ostream.h"
52 #include "llvm/System/Signals.h"
53 using namespace clang
;
56 class TUnit
: public TranslationUnit
{
58 TUnit(ASTUnit
*ast
, const std::string
&filename
)
59 : AST(ast
), Filename(filename
) { }
61 virtual ASTContext
&getASTContext() { return AST
->getASTContext(); }
63 llvm::OwningPtr
<ASTUnit
> AST
;
67 static llvm::cl::list
<ParsedSourceLocation
>
68 PointAtLocation("point-at", llvm::cl::Optional
,
69 llvm::cl::value_desc("source-location"),
70 llvm::cl::desc("Point at the given source location of the first AST file"));
73 PrintPoint
, // Just print the point-at node
74 PrintRefs
, // Print references of the point-at node
75 PrintDefs
, // Print definitions of the point-at node
76 PrintDecls
// Print declarations of the point-at node
79 static llvm::cl::opt
<ProgActions
>
81 llvm::cl::desc("Choose action to perform on the pointed-at AST node:"),
83 llvm::cl::init(PrintPoint
),
85 clEnumValN(PrintRefs
, "print-refs",
87 clEnumValN(PrintDefs
, "print-defs",
89 clEnumValN(PrintDecls
, "print-decls",
90 "Print declarations"),
93 static llvm::cl::opt
<bool>
94 DisableFree("disable-free",
95 llvm::cl::desc("Disable freeing of memory on exit"),
96 llvm::cl::init(false));
98 static void ProcessDecl(Decl
*D
) {
100 llvm::raw_ostream
&OS
= llvm::outs();
102 switch (ProgAction
) {
105 NamedDecl
*ND
= dyn_cast
<NamedDecl
>(D
);
109 DeclReferenceMap
RefMap(ND
->getASTContext());
110 for (DeclReferenceMap::astlocation_iterator
111 I
= RefMap
.refs_begin(ND
), E
= RefMap
.refs_end(ND
); I
!= E
; ++I
)
117 const Decl
*DefD
= 0;
118 if (FunctionDecl
*FD
= dyn_cast
<FunctionDecl
>(D
)) {
119 const FunctionDecl
*DFD
= 0;
122 } else if (VarDecl
*VD
= dyn_cast
<VarDecl
>(D
)) {
123 const VarDecl
*DVD
= 0;
124 VD
->getDefinition(DVD
);
129 ASTLocation(DefD
).print(OS
);
134 if (const FunctionDecl
*FD
= dyn_cast
<FunctionDecl
>(D
)) {
136 ASTLocation(FD
).print(OS
);
137 FD
= FD
->getPreviousDeclaration();
139 } else if (const VarDecl
*VD
= dyn_cast
<VarDecl
>(D
)) {
141 ASTLocation(VD
).print(OS
);
142 VD
= VD
->getPreviousDeclaration();
145 ASTLocation(D
).print(OS
);
151 static void ProcessNode(ASTLocation Node
, IndexProvider
&IdxProvider
) {
152 assert(Node
.isValid());
155 if (Node
.hasStmt()) {
156 if (DeclRefExpr
*RefExpr
= dyn_cast
<DeclRefExpr
>(Node
.getStmt()))
157 D
= RefExpr
->getDecl();
163 Entity
*Ent
= Entity::get(D
, IdxProvider
.getProgram());
164 // If there is no Entity associated with this Decl, it means that it's not
165 // visible to other translation units.
167 return ProcessDecl(D
);
169 // Find the "same" Decl in other translation units and print information.
170 for (IndexProvider::translation_unit_iterator
171 I
= IdxProvider
.translation_units_begin(Ent
),
172 E
= IdxProvider
.translation_units_end(Ent
); I
!= E
; ++I
) {
173 TUnit
*TU
= static_cast<TUnit
*>(*I
);
174 Decl
*OtherD
= Ent
->getDecl(TU
->getASTContext());
175 assert(OtherD
&& "Couldn't resolve Entity");
180 static llvm::cl::list
<std::string
>
181 InputFilenames(llvm::cl::Positional
, llvm::cl::desc("<input AST files>"));
183 int main(int argc
, char **argv
) {
184 llvm::sys::PrintStackTraceOnErrorSignal();
185 llvm::PrettyStackTraceProgram
X(argc
, argv
);
186 llvm::cl::ParseCommandLineOptions(argc
, argv
,
187 "LLVM 'Clang' Indexing Test Bed: http://clang.llvm.org\n");
192 IndexProvider
IdxProvider(Prog
);
193 llvm::SmallVector
<TUnit
*, 4> TUnits
;
195 // If no input was specified, read from stdin.
196 if (InputFilenames
.empty())
197 InputFilenames
.push_back("-");
199 for (unsigned i
= 0, e
= InputFilenames
.size(); i
!= e
; ++i
) {
200 const std::string
&InFile
= InputFilenames
[i
];
203 llvm::OwningPtr
<ASTUnit
> AST
;
205 AST
.reset(ASTUnit::LoadFromPCHFile(InFile
, FileMgr
, &ErrMsg
));
207 llvm::errs() << "[" << InFile
<< "] Error: " << ErrMsg
<< '\n';
211 TUnit
*TU
= new TUnit(AST
.take(), InFile
);
212 TUnits
.push_back(TU
);
214 IdxProvider
.IndexAST(TU
);
218 const std::string
&FirstFile
= TUnits
[0]->Filename
;
219 ASTUnit
*FirstAST
= TUnits
[0]->AST
.get();
221 if (!PointAtLocation
.empty()) {
222 const std::string
&Filename
= PointAtLocation
[0].FileName
;
223 const FileEntry
*File
= FileMgr
.getFile(Filename
);
225 // Safety check. Using an out-of-date AST file will only lead to crashes
226 // or incorrect results.
227 // FIXME: Check all the source files that make up the AST file.
228 const FileEntry
*ASTFile
= FileMgr
.getFile(FirstFile
);
229 if (File
->getModificationTime() > ASTFile
->getModificationTime()) {
230 llvm::errs() << "[" << FirstFile
<< "] Error: " <<
231 "Pointing at a source file which was modified after creating "
237 llvm::errs() << "File '" << Filename
<< "' does not exist\n";
240 unsigned Line
= PointAtLocation
[0].Line
;
241 unsigned Col
= PointAtLocation
[0].Column
;
244 FirstAST
->getSourceManager().getLocation(File
, Line
, Col
);
245 if (Loc
.isInvalid()) {
246 llvm::errs() << "[" << FirstFile
<< "] Error: " <<
247 "Couldn't resolve source location (invalid location)\n";
251 Node
= ResolveLocationInAST(FirstAST
->getASTContext(), Loc
);
252 if (Node
.isInvalid()) {
253 llvm::errs() << "[" << FirstFile
<< "] Error: " <<
254 "Couldn't resolve source location (no declaration found)\n";
259 if (Node
.isValid()) {
260 if (ProgAction
== PrintPoint
) {
261 llvm::raw_ostream
&OS
= llvm::outs();
263 if (const char *Comment
=
264 FirstAST
->getASTContext().getCommentForDecl(Node
.getDecl()))
265 OS
<< "Comment associated with this declaration:\n" << Comment
<< "\n";
267 ProcessNode(Node
, IdxProvider
);
272 for (int i
=0, e
=TUnits
.size(); i
!= e
; ++i
)
276 // Managed static deconstruction. Useful for making things like
277 // -time-passes usable.
278 llvm::llvm_shutdown();