summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2009-07-05 22:22:35 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2009-07-05 22:22:35 +0000
commit7b332d9ada3e2806a4d765000527f739f167791f (patch)
tree5b45f3cdaa38d6acd0f9126dad62fa1479af7eaa
parent9eec4ed6ca0dcf098580da9146b97e0841556d12 (diff)
downloadclang-7b332d9ada3e2806a4d765000527f739f167791f.tar.gz
clang-7b332d9ada3e2806a4d765000527f739f167791f.tar.bz2
clang-7b332d9ada3e2806a4d765000527f739f167791f.tar.xz
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
-rw-r--r--test/Index/_init.c2
-rw-r--r--test/Index/find-decls.c7
-rw-r--r--test/Index/find-defs.c8
-rw-r--r--test/Index/find-refs.c16
-rw-r--r--test/Index/foo.h4
-rw-r--r--test/Index/t1.c9
-rw-r--r--test/Index/t2.c8
-rwxr-xr-xtest/TestRunner.sh3
-rw-r--r--tools/index-test/CMakeLists.txt1
-rw-r--r--tools/index-test/Makefile2
-rw-r--r--tools/index-test/index-test.cpp204
-rwxr-xr-xutils/test/TestRunner.py2
12 files changed, 229 insertions, 37 deletions
diff --git a/test/Index/_init.c b/test/Index/_init.c
new file mode 100644
index 0000000000..24caaefcb1
--- /dev/null
+++ b/test/Index/_init.c
@@ -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
diff --git a/test/Index/find-decls.c b/test/Index/find-decls.c
new file mode 100644
index 0000000000..06b52e96d7
--- /dev/null
+++ b/test/Index/find-decls.c
@@ -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,'
diff --git a/test/Index/find-defs.c b/test/Index/find-defs.c
new file mode 100644
index 0000000000..d17dc0b142
--- /dev/null
+++ b/test/Index/find-defs.c
@@ -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,'
diff --git a/test/Index/find-refs.c b/test/Index/find-refs.c
new file mode 100644
index 0000000000..fea1f752fb
--- /dev/null
+++ b/test/Index/find-refs.c
@@ -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,'
diff --git a/test/Index/foo.h b/test/Index/foo.h
new file mode 100644
index 0000000000..2e3b403dea
--- /dev/null
+++ b/test/Index/foo.h
@@ -0,0 +1,4 @@
+extern int global_var;
+
+void foo_func(int param1);
+void bar_func(void);
diff --git a/test/Index/t1.c b/test/Index/t1.c
new file mode 100644
index 0000000000..1ff89ca34b
--- /dev/null
+++ b/test/Index/t1.c
@@ -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();
+}
diff --git a/test/Index/t2.c b/test/Index/t2.c
new file mode 100644
index 0000000000..8e405cc367
--- /dev/null
+++ b/test/Index/t2.c
@@ -0,0 +1,8 @@
+#include "foo.h"
+
+int global_var = 10;
+
+void bar_func(void) {
+ global_var += 100;
+ foo_func(global_var);
+}
diff --git a/test/TestRunner.sh b/test/TestRunner.sh
index bb20728578..07451eb485 100755
--- a/test/TestRunner.sh
+++ b/test/TestRunner.sh
@@ -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
diff --git a/tools/index-test/CMakeLists.txt b/tools/index-test/CMakeLists.txt
index 09f4fc12c1..880539bbe3 100644
--- a/tools/index-test/CMakeLists.txt
+++ b/tools/index-test/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_NO_RTTI 1)
set( LLVM_USED_LIBS
+ clangIndex
clangFrontend
clangSema
clangAST
diff --git a/tools/index-test/Makefile b/tools/index-test/Makefile
index 4fbde29198..cec0eee286 100644
--- a/tools/index-test/Makefile
+++ b/tools/index-test/Makefile
@@ -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
diff --git a/tools/index-test/index-test.cpp b/tools/index-test/index-test.cpp
index 0fa0d5a466..5043e3e62b 100644
--- a/tools/index-test/index-test.cpp
+++ b/tools/index-test/index-test.cpp
@@ -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.
diff --git a/utils/test/TestRunner.py b/utils/test/TestRunner.py
index 9020622350..5625cb3c5b 100755
--- a/utils/test/TestRunner.py
+++ b/utils/test/TestRunner.py
@@ -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 = []