2009-06-26 02:22:52 +08:00
|
|
|
//===--- index-test.cpp - Indexing test bed -------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This utility may be invoked in the following manner:
|
|
|
|
// index-test --help - Output help info.
|
|
|
|
// index-test [options] - Read from stdin.
|
|
|
|
// index-test [options] file - Read from "file".
|
|
|
|
// index-test [options] file1 file2 - Read these files.
|
|
|
|
//
|
|
|
|
// Files must be AST files.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2009-07-07 15:14:55 +08:00
|
|
|
// -point-at [file:line:column]
|
2009-06-26 05:54:50 +08:00
|
|
|
// Point at a declaration/statement/expression. If no other operation is
|
|
|
|
// specified, prints some info about it.
|
2009-06-26 02:22:52 +08:00
|
|
|
//
|
2009-07-06 06:22:35 +08:00
|
|
|
// -print-refs
|
2009-07-07 05:34:20 +08:00
|
|
|
// Print ASTLocations that reference the -point-at node
|
2009-07-06 06:22:35 +08:00
|
|
|
//
|
|
|
|
// -print-defs
|
2009-07-07 05:34:20 +08:00
|
|
|
// Print ASTLocations that define the -point-at node
|
2009-07-06 06:22:35 +08:00
|
|
|
//
|
|
|
|
// -print-decls
|
2009-07-07 05:34:20 +08:00
|
|
|
// Print ASTLocations that declare the -point-at node
|
2009-07-06 06:22:35 +08:00
|
|
|
//
|
2009-06-26 02:22:52 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-07-06 06:22:35 +08:00
|
|
|
#include "clang/Index/Program.h"
|
|
|
|
#include "clang/Index/IndexProvider.h"
|
|
|
|
#include "clang/Index/Entity.h"
|
|
|
|
#include "clang/Index/TranslationUnit.h"
|
2009-07-07 05:34:47 +08:00
|
|
|
#include "clang/Index/ASTLocation.h"
|
|
|
|
#include "clang/Index/DeclReferenceMap.h"
|
2009-07-07 05:35:02 +08:00
|
|
|
#include "clang/Index/Utils.h"
|
2009-06-26 02:22:52 +08:00
|
|
|
#include "clang/Frontend/ASTUnit.h"
|
|
|
|
#include "clang/Frontend/CommandLineSourceLoc.h"
|
|
|
|
#include "clang/AST/Decl.h"
|
2009-07-06 06:22:35 +08:00
|
|
|
#include "clang/AST/Expr.h"
|
2009-06-26 02:22:52 +08:00
|
|
|
#include "clang/Basic/FileManager.h"
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
|
|
#include "llvm/Support/PrettyStackTrace.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include "llvm/System/Signals.h"
|
|
|
|
using namespace clang;
|
2009-07-06 06:22:35 +08:00
|
|
|
using namespace idx;
|
2009-06-26 02:22:52 +08:00
|
|
|
|
2009-07-06 06:22:35 +08:00
|
|
|
class TUnit : public TranslationUnit {
|
|
|
|
public:
|
|
|
|
TUnit(ASTUnit *ast, const std::string &filename)
|
|
|
|
: AST(ast), Filename(filename) { }
|
|
|
|
|
|
|
|
virtual ASTContext &getASTContext() { return AST->getASTContext(); }
|
|
|
|
|
|
|
|
llvm::OwningPtr<ASTUnit> AST;
|
|
|
|
std::string Filename;
|
|
|
|
};
|
2009-06-26 02:22:52 +08:00
|
|
|
|
|
|
|
static llvm::cl::list<ParsedSourceLocation>
|
|
|
|
PointAtLocation("point-at", llvm::cl::Optional,
|
|
|
|
llvm::cl::value_desc("source-location"),
|
|
|
|
llvm::cl::desc("Point at the given source location of the first AST file"));
|
|
|
|
|
2009-07-06 06:22:35 +08:00
|
|
|
enum ProgActions {
|
|
|
|
PrintPoint, // Just print the point-at node
|
|
|
|
PrintRefs, // Print references of the point-at node
|
|
|
|
PrintDefs, // Print definitions of the point-at node
|
|
|
|
PrintDecls // Print declarations of the point-at node
|
|
|
|
};
|
|
|
|
|
|
|
|
static llvm::cl::opt<ProgActions>
|
|
|
|
ProgAction(
|
|
|
|
llvm::cl::desc("Choose action to perform on the pointed-at AST node:"),
|
|
|
|
llvm::cl::ZeroOrMore,
|
|
|
|
llvm::cl::init(PrintPoint),
|
|
|
|
llvm::cl::values(
|
|
|
|
clEnumValN(PrintRefs, "print-refs",
|
|
|
|
"Print references"),
|
|
|
|
clEnumValN(PrintDefs, "print-defs",
|
|
|
|
"Print definitions"),
|
|
|
|
clEnumValN(PrintDecls, "print-decls",
|
|
|
|
"Print declarations"),
|
|
|
|
clEnumValEnd));
|
|
|
|
|
2009-06-26 02:22:52 +08:00
|
|
|
static llvm::cl::opt<bool>
|
|
|
|
DisableFree("disable-free",
|
|
|
|
llvm::cl::desc("Disable freeing of memory on exit"),
|
|
|
|
llvm::cl::init(false));
|
|
|
|
|
2009-07-14 11:18:40 +08:00
|
|
|
static bool HadErrors = false;
|
|
|
|
|
2009-07-06 06:22:35 +08:00
|
|
|
static void ProcessDecl(Decl *D) {
|
|
|
|
assert(D);
|
|
|
|
llvm::raw_ostream &OS = llvm::outs();
|
|
|
|
|
|
|
|
switch (ProgAction) {
|
|
|
|
default: assert(0);
|
|
|
|
case PrintRefs: {
|
|
|
|
NamedDecl *ND = dyn_cast<NamedDecl>(D);
|
|
|
|
if (!ND)
|
|
|
|
return;
|
|
|
|
|
|
|
|
DeclReferenceMap RefMap(ND->getASTContext());
|
2009-07-07 05:34:20 +08:00
|
|
|
for (DeclReferenceMap::astlocation_iterator
|
2009-07-06 06:22:35 +08:00
|
|
|
I = RefMap.refs_begin(ND), E = RefMap.refs_end(ND); I != E; ++I)
|
|
|
|
I->print(OS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PrintDefs: {
|
|
|
|
const Decl *DefD = 0;
|
|
|
|
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
|
|
|
const FunctionDecl *DFD = 0;
|
|
|
|
FD->getBody(DFD);
|
|
|
|
DefD = DFD;
|
|
|
|
} else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
|
|
|
const VarDecl *DVD = 0;
|
|
|
|
VD->getDefinition(DVD);
|
|
|
|
DefD = DVD;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DefD)
|
2009-07-07 05:34:20 +08:00
|
|
|
ASTLocation(DefD).print(OS);
|
2009-07-06 06:22:35 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PrintDecls :
|
2009-07-18 16:50:35 +08:00
|
|
|
for (Decl::redecl_iterator I = D->redecls_begin(),
|
|
|
|
E = D->redecls_end(); I != E; ++I)
|
|
|
|
ASTLocation(*I).print(OS);
|
2009-07-06 06:22:35 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-07 05:35:26 +08:00
|
|
|
static void ProcessASTLocation(ASTLocation ASTLoc, IndexProvider &IdxProvider) {
|
|
|
|
assert(ASTLoc.isValid());
|
2009-07-06 06:22:35 +08:00
|
|
|
|
2009-07-19 05:17:58 +08:00
|
|
|
Decl *D = ASTLoc.getReferencedDecl();
|
2009-07-14 11:18:40 +08:00
|
|
|
if (D == 0) {
|
2009-07-21 08:05:10 +08:00
|
|
|
llvm::errs() << "Error: Couldn't get referenced Decl for the ASTLocation\n";
|
2009-07-14 11:18:40 +08:00
|
|
|
HadErrors = true;
|
|
|
|
return;
|
|
|
|
}
|
2009-07-06 06:22:35 +08:00
|
|
|
|
2009-07-21 08:07:06 +08:00
|
|
|
Entity Ent = Entity::get(D, IdxProvider.getProgram());
|
|
|
|
if (Ent.isInvalid() || Ent.isInternalToTU())
|
2009-07-06 06:22:35 +08:00
|
|
|
return ProcessDecl(D);
|
|
|
|
|
|
|
|
// Find the "same" Decl in other translation units and print information.
|
|
|
|
for (IndexProvider::translation_unit_iterator
|
|
|
|
I = IdxProvider.translation_units_begin(Ent),
|
|
|
|
E = IdxProvider.translation_units_end(Ent); I != E; ++I) {
|
|
|
|
TUnit *TU = static_cast<TUnit*>(*I);
|
2009-07-21 08:07:06 +08:00
|
|
|
Decl *OtherD = Ent.getDecl(TU->getASTContext());
|
2009-07-06 06:22:35 +08:00
|
|
|
assert(OtherD && "Couldn't resolve Entity");
|
|
|
|
ProcessDecl(OtherD);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-26 02:22:52 +08:00
|
|
|
static llvm::cl::list<std::string>
|
|
|
|
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
llvm::sys::PrintStackTraceOnErrorSignal();
|
|
|
|
llvm::PrettyStackTraceProgram X(argc, argv);
|
|
|
|
llvm::cl::ParseCommandLineOptions(argc, argv,
|
|
|
|
"LLVM 'Clang' Indexing Test Bed: http://clang.llvm.org\n");
|
|
|
|
|
|
|
|
FileManager FileMgr;
|
2009-07-06 06:22:35 +08:00
|
|
|
|
|
|
|
Program Prog;
|
|
|
|
IndexProvider IdxProvider(Prog);
|
|
|
|
llvm::SmallVector<TUnit*, 4> TUnits;
|
2009-06-26 02:22:52 +08:00
|
|
|
|
|
|
|
// If no input was specified, read from stdin.
|
|
|
|
if (InputFilenames.empty())
|
|
|
|
InputFilenames.push_back("-");
|
|
|
|
|
2009-07-06 06:22:35 +08:00
|
|
|
for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
|
|
|
|
const std::string &InFile = InputFilenames[i];
|
|
|
|
|
|
|
|
std::string ErrMsg;
|
|
|
|
llvm::OwningPtr<ASTUnit> AST;
|
2009-06-26 02:22:52 +08:00
|
|
|
|
2009-07-06 06:22:35 +08:00
|
|
|
AST.reset(ASTUnit::LoadFromPCHFile(InFile, FileMgr, &ErrMsg));
|
|
|
|
if (!AST) {
|
|
|
|
llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
|
|
|
|
return 1;
|
|
|
|
}
|
2009-06-26 02:22:52 +08:00
|
|
|
|
2009-07-06 06:22:35 +08:00
|
|
|
TUnit *TU = new TUnit(AST.take(), InFile);
|
|
|
|
TUnits.push_back(TU);
|
|
|
|
|
|
|
|
IdxProvider.IndexAST(TU);
|
2009-06-26 02:22:52 +08:00
|
|
|
}
|
|
|
|
|
2009-07-07 05:35:26 +08:00
|
|
|
ASTLocation ASTLoc;
|
2009-07-06 06:22:35 +08:00
|
|
|
const std::string &FirstFile = TUnits[0]->Filename;
|
|
|
|
ASTUnit *FirstAST = TUnits[0]->AST.get();
|
2009-06-26 02:22:52 +08:00
|
|
|
|
|
|
|
if (!PointAtLocation.empty()) {
|
|
|
|
const std::string &Filename = PointAtLocation[0].FileName;
|
|
|
|
const FileEntry *File = FileMgr.getFile(Filename);
|
2009-06-26 06:15:12 +08:00
|
|
|
|
|
|
|
// Safety check. Using an out-of-date AST file will only lead to crashes
|
|
|
|
// or incorrect results.
|
|
|
|
// FIXME: Check all the source files that make up the AST file.
|
2009-07-06 06:22:35 +08:00
|
|
|
const FileEntry *ASTFile = FileMgr.getFile(FirstFile);
|
2009-06-26 06:15:12 +08:00
|
|
|
if (File->getModificationTime() > ASTFile->getModificationTime()) {
|
2009-07-06 06:22:35 +08:00
|
|
|
llvm::errs() << "[" << FirstFile << "] Error: " <<
|
2009-06-26 06:15:12 +08:00
|
|
|
"Pointing at a source file which was modified after creating "
|
|
|
|
"the AST file\n";
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-06-26 02:22:52 +08:00
|
|
|
if (File == 0) {
|
|
|
|
llvm::errs() << "File '" << Filename << "' does not exist\n";
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
unsigned Line = PointAtLocation[0].Line;
|
|
|
|
unsigned Col = PointAtLocation[0].Column;
|
|
|
|
|
2009-07-06 06:22:35 +08:00
|
|
|
SourceLocation Loc =
|
|
|
|
FirstAST->getSourceManager().getLocation(File, Line, Col);
|
2009-06-26 02:22:52 +08:00
|
|
|
if (Loc.isInvalid()) {
|
2009-07-06 06:22:35 +08:00
|
|
|
llvm::errs() << "[" << FirstFile << "] Error: " <<
|
2009-06-26 02:22:52 +08:00
|
|
|
"Couldn't resolve source location (invalid location)\n";
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-07-07 05:35:26 +08:00
|
|
|
ASTLoc = ResolveLocationInAST(FirstAST->getASTContext(), Loc);
|
|
|
|
if (ASTLoc.isInvalid()) {
|
2009-07-06 06:22:35 +08:00
|
|
|
llvm::errs() << "[" << FirstFile << "] Error: " <<
|
2009-06-26 02:22:52 +08:00
|
|
|
"Couldn't resolve source location (no declaration found)\n";
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-07 05:35:26 +08:00
|
|
|
if (ASTLoc.isValid()) {
|
2009-07-06 06:22:35 +08:00
|
|
|
if (ProgAction == PrintPoint) {
|
|
|
|
llvm::raw_ostream &OS = llvm::outs();
|
2009-07-07 05:35:26 +08:00
|
|
|
ASTLoc.print(OS);
|
2009-07-06 06:22:35 +08:00
|
|
|
if (const char *Comment =
|
2009-07-07 05:35:26 +08:00
|
|
|
FirstAST->getASTContext().getCommentForDecl(ASTLoc.getDecl()))
|
2009-07-06 06:22:35 +08:00
|
|
|
OS << "Comment associated with this declaration:\n" << Comment << "\n";
|
|
|
|
} else {
|
2009-07-07 05:35:26 +08:00
|
|
|
ProcessASTLocation(ASTLoc, IdxProvider);
|
2009-06-26 02:22:52 +08:00
|
|
|
}
|
|
|
|
}
|
2009-07-14 11:18:40 +08:00
|
|
|
|
|
|
|
if (HadErrors)
|
|
|
|
return 1;
|
2009-06-26 02:22:52 +08:00
|
|
|
|
2009-07-06 06:22:35 +08:00
|
|
|
if (!DisableFree) {
|
|
|
|
for (int i=0, e=TUnits.size(); i != e; ++i)
|
|
|
|
delete TUnits[i];
|
|
|
|
}
|
2009-06-26 02:22:52 +08:00
|
|
|
|
|
|
|
// Managed static deconstruction. Useful for making things like
|
|
|
|
// -time-passes usable.
|
|
|
|
llvm::llvm_shutdown();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|