зеркало из https://github.com/microsoft/clang-1.git
Make use of the Index library through the index-test tool.
'index-test' is now able to provide additional info for a Decl, through multiple AST files: -Find declarations -Find definitions -Find references git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74803 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
9eec4ed6ca
Коммит
7b332d9ada
|
@ -0,0 +1,2 @@
|
|||
// RUN: clang-cc -emit-pch %S/t1.c -o %T/t1.ast &&
|
||||
// RUN: clang-cc -emit-pch %S/t2.c -o %T/t2.ast
|
|
@ -0,0 +1,7 @@
|
|||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:8:7 -print-decls | count 3 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:8:7 -print-decls | grep 'foo.h:4:6,' | count 2 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:8:7 -print-decls | grep 't2.c:5:6,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:5:47 -print-decls | count 1 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:5:47 -print-decls | grep 't1.c:5:12,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:6:20 -print-decls | count 1 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:6:20 -print-decls | grep 't1.c:3:19,'
|
|
@ -0,0 +1,8 @@
|
|||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:1:14 -print-defs | count 1 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:1:14 -print-defs | grep 't2.c:3:5,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:3:9 -print-defs | count 1 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:3:9 -print-defs | grep 't1.c:3:6,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:4:9 -print-defs | count 1 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:4:9 -print-defs | grep 't2.c:5:6,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:8:7 -print-defs | count 1 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:8:7 -print-defs | grep 't2.c:5:6,'
|
|
@ -0,0 +1,16 @@
|
|||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:1:14 -print-refs | count 3 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:1:14 -print-refs | grep 't1.c:4:19,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:1:14 -print-refs | grep 't2.c:6:3,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:1:14 -print-refs | grep 't2.c:7:12,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:3:9 -print-refs | count 1 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:3:9 -print-refs | grep 't2.c:7:3,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:4:9 -print-refs | count 1 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/foo.h:4:9 -print-refs | grep 't1.c:8:3,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:3:22 -print-refs | count 1 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:3:22 -print-refs | grep 't1.c:6:17,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:4:11 -print-refs | count 1 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:4:11 -print-refs | grep 't1.c:6:5,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:5:30 -print-refs | count 3 &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:5:30 -print-refs | grep 't1.c:5:27,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:5:30 -print-refs | grep 't1.c:5:44,' &&
|
||||
// RUN: index-test %T/t1.ast %T/t2.ast -point-at %S/t1.c:5:30 -print-refs | grep 't1.c:6:26,'
|
|
@ -0,0 +1,4 @@
|
|||
extern int global_var;
|
||||
|
||||
void foo_func(int param1);
|
||||
void bar_func(void);
|
|
@ -0,0 +1,9 @@
|
|||
#include "foo.h"
|
||||
|
||||
void foo_func(int param1) {
|
||||
int local_var = global_var;
|
||||
for (int for_var = 100; for_var < 500; ++for_var) {
|
||||
local_var = param1 + for_var;
|
||||
}
|
||||
bar_func();
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include "foo.h"
|
||||
|
||||
int global_var = 10;
|
||||
|
||||
void bar_func(void) {
|
||||
global_var += 100;
|
||||
foo_func(global_var);
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
# %S - Replaced with the directory where the input file resides
|
||||
# %prcontext - prcontext.tcl script
|
||||
# %t - temporary file name (derived from testcase name)
|
||||
# %T - directory of temporary file name
|
||||
#
|
||||
|
||||
FILENAME=$1
|
||||
|
@ -19,6 +20,7 @@ SUBST=$1
|
|||
FILEDIR=`dirname $TESTNAME`
|
||||
|
||||
OUTPUT=Output/$1.out
|
||||
OUTPUTDIR=`dirname $OUTPUT`
|
||||
|
||||
# create the output directory if it does not already exist
|
||||
mkdir -p `dirname $OUTPUT` > /dev/null 2>&1
|
||||
|
@ -86,6 +88,7 @@ grep 'RUN:' $FILENAME | \
|
|||
-e "s|%s|$SUBST|g" \
|
||||
-e "s|%S|$FILEDIR|g" \
|
||||
-e "s|%prcontext|prcontext.tcl|g" \
|
||||
-e "s|%T|$OUTPUTDIR|g" \
|
||||
-e "s|%t|$TEMPOUTPUT|g" > $SCRIPT
|
||||
|
||||
IS_XFAIL=0
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
set(LLVM_NO_RTTI 1)
|
||||
|
||||
set( LLVM_USED_LIBS
|
||||
clangIndex
|
||||
clangFrontend
|
||||
clangSema
|
||||
clangAST
|
||||
|
|
|
@ -18,6 +18,6 @@ TOOL_NO_EXPORTS = 1
|
|||
include $(LEVEL)/Makefile.config
|
||||
|
||||
LINK_COMPONENTS := bitreader
|
||||
USEDLIBS = clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a
|
||||
USEDLIBS = clangIndex.a clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
||||
|
|
|
@ -21,35 +21,162 @@
|
|||
// Point at a declaration/statement/expression. If no other operation is
|
||||
// specified, prints some info about it.
|
||||
//
|
||||
// -print-refs
|
||||
// Print ASTNodes that reference the -point-at node
|
||||
//
|
||||
// -print-defs
|
||||
// Print ASTNodes that define the -point-at node
|
||||
//
|
||||
// -print-decls
|
||||
// Print ASTNodes that declare the -point-at node
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Index/Program.h"
|
||||
#include "clang/Index/IndexProvider.h"
|
||||
#include "clang/Index/Entity.h"
|
||||
#include "clang/Index/TranslationUnit.h"
|
||||
#include "clang/Frontend/ASTUnit.h"
|
||||
#include "clang/Frontend/Utils.h"
|
||||
#include "clang/Frontend/CommandLineSourceLoc.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ASTNode.h"
|
||||
#include "clang/AST/DeclReferenceMap.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/ADT/STLExtras.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;
|
||||
using namespace idx;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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"));
|
||||
|
||||
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));
|
||||
|
||||
static llvm::cl::opt<bool>
|
||||
DisableFree("disable-free",
|
||||
llvm::cl::desc("Disable freeing of memory on exit"),
|
||||
llvm::cl::init(false));
|
||||
|
||||
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());
|
||||
for (DeclReferenceMap::astnode_iterator
|
||||
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)
|
||||
ASTNode(DefD).print(OS);
|
||||
break;
|
||||
}
|
||||
|
||||
case PrintDecls :
|
||||
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
while (FD) {
|
||||
ASTNode(FD).print(OS);
|
||||
FD = FD->getPreviousDeclaration();
|
||||
}
|
||||
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
||||
while (VD) {
|
||||
ASTNode(VD).print(OS);
|
||||
VD = VD->getPreviousDeclaration();
|
||||
}
|
||||
} else
|
||||
ASTNode(D).print(OS);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void ProcessNode(ASTNode Node, IndexProvider &IdxProvider) {
|
||||
assert(Node.isValid());
|
||||
|
||||
Decl *D = 0;
|
||||
if (Node.hasStmt()) {
|
||||
if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(Node.getStmt()))
|
||||
D = RefExpr->getDecl();
|
||||
} else {
|
||||
D = Node.getDecl();
|
||||
}
|
||||
assert(D);
|
||||
|
||||
Entity *Ent = Entity::get(D, IdxProvider.getProgram());
|
||||
// If there is no Entity associated with this Decl, it means that it's not
|
||||
// visible to other translation units.
|
||||
if (!Ent)
|
||||
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);
|
||||
Decl *OtherD = Ent->getDecl(TU->getASTContext());
|
||||
assert(OtherD && "Couldn't resolve Entity");
|
||||
ProcessDecl(OtherD);
|
||||
}
|
||||
}
|
||||
|
||||
static llvm::cl::list<std::string>
|
||||
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
|
||||
|
||||
|
@ -60,25 +187,36 @@ int main(int argc, char **argv) {
|
|||
"LLVM 'Clang' Indexing Test Bed: http://clang.llvm.org\n");
|
||||
|
||||
FileManager FileMgr;
|
||||
|
||||
Program Prog;
|
||||
IndexProvider IdxProvider(Prog);
|
||||
llvm::SmallVector<TUnit*, 4> TUnits;
|
||||
|
||||
// If no input was specified, read from stdin.
|
||||
if (InputFilenames.empty())
|
||||
InputFilenames.push_back("-");
|
||||
|
||||
// FIXME: Only the first AST file is used for now.
|
||||
for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
|
||||
const std::string &InFile = InputFilenames[i];
|
||||
|
||||
std::string ErrMsg;
|
||||
llvm::OwningPtr<ASTUnit> AST;
|
||||
|
||||
const std::string &InFile = InputFilenames[0];
|
||||
|
||||
std::string ErrMsg;
|
||||
llvm::OwningPtr<ASTUnit> AST;
|
||||
AST.reset(ASTUnit::LoadFromPCHFile(InFile, FileMgr, &ErrMsg));
|
||||
if (!AST) {
|
||||
llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
AST.reset(ASTUnit::LoadFromPCHFile(InFile, FileMgr, &ErrMsg));
|
||||
if (!AST) {
|
||||
llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
|
||||
return 1;
|
||||
TUnit *TU = new TUnit(AST.take(), InFile);
|
||||
TUnits.push_back(TU);
|
||||
|
||||
IdxProvider.IndexAST(TU);
|
||||
}
|
||||
|
||||
ASTNode Node;
|
||||
const std::string &FirstFile = TUnits[0]->Filename;
|
||||
ASTUnit *FirstAST = TUnits[0]->AST.get();
|
||||
|
||||
if (!PointAtLocation.empty()) {
|
||||
const std::string &Filename = PointAtLocation[0].FileName;
|
||||
|
@ -87,9 +225,9 @@ int main(int argc, char **argv) {
|
|||
// 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.
|
||||
const FileEntry *ASTFile = FileMgr.getFile(InFile);
|
||||
const FileEntry *ASTFile = FileMgr.getFile(FirstFile);
|
||||
if (File->getModificationTime() > ASTFile->getModificationTime()) {
|
||||
llvm::errs() << "[" << InFile << "] Error: " <<
|
||||
llvm::errs() << "[" << FirstFile << "] Error: " <<
|
||||
"Pointing at a source file which was modified after creating "
|
||||
"the AST file\n";
|
||||
return 1;
|
||||
|
@ -102,44 +240,38 @@ int main(int argc, char **argv) {
|
|||
unsigned Line = PointAtLocation[0].Line;
|
||||
unsigned Col = PointAtLocation[0].Column;
|
||||
|
||||
SourceLocation Loc = AST->getSourceManager().getLocation(File, Line, Col);
|
||||
SourceLocation Loc =
|
||||
FirstAST->getSourceManager().getLocation(File, Line, Col);
|
||||
if (Loc.isInvalid()) {
|
||||
llvm::errs() << "[" << InFile << "] Error: " <<
|
||||
llvm::errs() << "[" << FirstFile << "] Error: " <<
|
||||
"Couldn't resolve source location (invalid location)\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
Node = ResolveLocationInAST(AST->getASTContext(), Loc);
|
||||
Node = ResolveLocationInAST(FirstAST->getASTContext(), Loc);
|
||||
if (Node.isInvalid()) {
|
||||
llvm::errs() << "[" << InFile << "] Error: " <<
|
||||
llvm::errs() << "[" << FirstFile << "] Error: " <<
|
||||
"Couldn't resolve source location (no declaration found)\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Node.isValid()) {
|
||||
llvm::raw_ostream &OS = llvm::outs();
|
||||
OS << "Declaration node at point: " << Node.getDecl()->getDeclKindName()
|
||||
<< " ";
|
||||
if (NamedDecl *ND = dyn_cast<NamedDecl>(Node.getDecl()))
|
||||
OS << ND->getNameAsString();
|
||||
OS << "\n";
|
||||
|
||||
if (const char *Comment =
|
||||
AST->getASTContext().getCommentForDecl(Node.getDecl()))
|
||||
OS << "Comment associated with this declaration:\n" << Comment << "\n";
|
||||
|
||||
if (Node.getStmt()) {
|
||||
OS << "Statement node at point: " << Node.getStmt()->getStmtClassName()
|
||||
<< " ";
|
||||
Node.getStmt()->printPretty(OS, AST->getASTContext(), 0,
|
||||
PrintingPolicy(AST->getASTContext().getLangOptions()));
|
||||
OS << "\n";
|
||||
if (ProgAction == PrintPoint) {
|
||||
llvm::raw_ostream &OS = llvm::outs();
|
||||
Node.print(OS);
|
||||
if (const char *Comment =
|
||||
FirstAST->getASTContext().getCommentForDecl(Node.getDecl()))
|
||||
OS << "Comment associated with this declaration:\n" << Comment << "\n";
|
||||
} else {
|
||||
ProcessNode(Node, IdxProvider);
|
||||
}
|
||||
}
|
||||
|
||||
if (DisableFree)
|
||||
AST.take();
|
||||
if (!DisableFree) {
|
||||
for (int i=0, e=TUnits.size(); i != e; ++i)
|
||||
delete TUnits[i];
|
||||
}
|
||||
|
||||
// Managed static deconstruction. Useful for making things like
|
||||
// -time-passes usable.
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# %llvmgxx - llvm-g++ command
|
||||
# %prcontext - prcontext.tcl script
|
||||
# %t - temporary file name (derived from testcase name)
|
||||
# %T - directory of temporary file name
|
||||
#
|
||||
|
||||
import errno
|
||||
|
@ -116,6 +117,7 @@ def runOneTest(FILENAME, SUBST, OUTPUT, TESTNAME, CLANG, CLANGCC,
|
|||
('%llvmgxx','llvm-g++ -emit-llvm -w'),
|
||||
('%prcontext','prcontext.tcl'),
|
||||
('%t',TEMPOUTPUT),
|
||||
('%T',os.path.dirname(TEMPOUTPUT)),
|
||||
(' clang ', ' ' + CLANG + ' '),
|
||||
(' clang-cc ', ' ' + CLANGCC + ' ')]
|
||||
scriptLines = []
|
||||
|
|
Загрузка…
Ссылка в новой задаче