[cfe-commits] r74197 - in /cfe/trunk: include/clang/Frontend/Utils.h lib/Frontend/CMakeLists.txt lib/Frontend/ResolveLocation.cpp
Douglas Gregor
dgregor at apple.com
Thu Jun 25 15:36:29 PDT 2009
On Jun 25, 2009, at 11:22 AM, Argiris Kirtzidis wrote:
> Author: akirtzidis
> Date: Thu Jun 25 13:22:41 2009
> New Revision: 74197
>
> URL: http://llvm.org/viewvc/llvm-project?rev=74197&view=rev
> Log:
> Introduce the ResolveLocationInAST function which takes an
> ASTContext and a SourceLocation and it resolves it into a <Decl*,
> Stmt*> pair.
>
> Decl* is the declaration associated with this source location and
> Stmt* is the statement/expression that the location points to.
> If the location does not point to a statement node, Stmt* is null.
>
> ResolveLocationInAST (along with converting a file:line:column
> triplet to a SourceLocation) will be useful for an IDE client and
> for clang's test suite.
Cool! A few comments below (but not many).
> Added:
> cfe/trunk/lib/Frontend/ResolveLocation.cpp
> Modified:
> cfe/trunk/include/clang/Frontend/Utils.h
> cfe/trunk/lib/Frontend/CMakeLists.txt
>
> Modified: cfe/trunk/include/clang/Frontend/Utils.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/Utils.h?rev=74197&r1=74196&r2=74197&view=diff
>
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- cfe/trunk/include/clang/Frontend/Utils.h (original)
> +++ cfe/trunk/include/clang/Frontend/Utils.h Thu Jun 25 13:22:41 2009
> @@ -32,6 +32,10 @@
> class SourceManager;
> class PreprocessorFactory;
> class LangOptions;
> +class Decl;
> +class Stmt;
> +class ASTContext;
> +class SourceLocation;
>
> /// ProcessWarningOptions - Initialize the diagnostic client and
> process the
> /// warning options specified on the command line.
> @@ -74,6 +78,33 @@
> /// a seekable stream.
> void CacheTokens(Preprocessor& PP, llvm::raw_fd_ostream* OS);
>
> +/// \brief Returns the AST node that a source location points to.
> +///
> +/// Returns a pair of Decl* and Stmt*. If no AST node is found for
> the source
> +/// location, the pair will contain null pointers.
> +///
> +/// If the source location points to just a declaration, the
> statement part of
> +/// the pair will be null, e.g.,
> +/// @code
> +/// int foo;
> +/// @endcode
> +/// If the source location points at 'foo', the pair will contain
> the VarDecl
> +/// of foo and a null Stmt.
> +///
> +/// If the source location points to a statement node, the returned
> declaration
> +/// will be the immediate 'parent' declaration of the statement
> node, e.g.,
> +/// @code
> +/// void f() {
> +/// int foo = 100;
> +/// ++foo;
> +/// }
> +/// @endcode
> +/// Pointing at '100' will return a <VarDecl 'foo', IntegerLiteral
> '100'> pair.
> +/// Pointing at '++foo' will return a <FunctionDecl 'f',
> UnaryOperator> pair.
> +///
> +std::pair<Decl *, Stmt *> ResolveLocationInAST(ASTContext &Ctx,
> + SourceLocation Loc);
> +
> } // end namespace clang
>
> #endif
>
> Modified: cfe/trunk/lib/Frontend/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CMakeLists.txt?rev=74197&r1=74196&r2=74197&view=diff
>
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- cfe/trunk/lib/Frontend/CMakeLists.txt (original)
> +++ cfe/trunk/lib/Frontend/CMakeLists.txt Thu Jun 25 13:22:41 2009
> @@ -26,6 +26,7 @@
> PlistDiagnostics.cpp
> PrintParserCallbacks.cpp
> PrintPreprocessedOutput.cpp
> + ResolveLocation.cpp
> RewriteBlocks.cpp
> RewriteMacros.cpp
> RewriteObjC.cpp
>
> Added: cfe/trunk/lib/Frontend/ResolveLocation.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ResolveLocation.cpp?rev=74197&view=auto
>
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- cfe/trunk/lib/Frontend/ResolveLocation.cpp (added)
> +++ cfe/trunk/lib/Frontend/ResolveLocation.cpp Thu Jun 25 13:22:41
> 2009
> @@ -0,0 +1,322 @@
> +//===--- ResolveLocation.cpp - Source location resolver ---------*-
> C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open
> Source
> +// License. See LICENSE.TXT for details.
> +//
> +//
> =
> =
> =
> ----------------------------------------------------------------------=
> ==//
> +//
> +// This defines the ResolveLocationInAST function, which resolves a
> +// source location into a <Decl *, Stmt *> pair.
> +//
> +//
> =
> =
> =
> ----------------------------------------------------------------------=
> ==//
> +
> +#include "clang/Frontend/Utils.h"
> +#include "clang/AST/DeclVisitor.h"
> +#include "clang/AST/StmtVisitor.h"
> +#include "clang/Lex/Lexer.h"
> +#include "clang/Basic/SourceManager.h"
> +#include "llvm/Support/Compiler.h"
> +using namespace clang;
> +
> +namespace {
> +
> +/// \brief Base for the LocResolver classes. Mostly does source
> range checking.
> +class VISIBILITY_HIDDEN LocResolverBase {
> +protected:
> + ASTContext &Ctx;
> + SourceLocation Loc;
> +
> + Decl *Dcl;
> + Stmt *Stm;
> + bool PassedLoc;
> +
> + /// \brief Checks whether Loc is in the source range of 'D'.
> + ///
> + /// If it is, updates Dcl. If Loc is passed the source range, it
> sets
> + /// PassedLoc, otherwise it does nothing.
> + void CheckRange(Decl *D);
> +
> + /// \brief Checks whether Loc is in the source range of 'Node'.
> + ///
> + /// If it is, updates Stm. If Loc is passed the source range, it
> sets
> + /// PassedLoc, otherwise it does nothing.
> + void CheckRange(Stmt *Node);
> +
> + /// \brief Updates the end source range to cover the full length
> of the token
> + /// positioned at the end of the source range.
> + ///
> + /// e.g.,
> + /// @code
> + /// int foo
> + /// ^ ^
> + /// @endcode
> + /// will be updated to
> + /// @code
> + /// int foo
> + /// ^ ^
> + /// @endcode
> + void FixRange(SourceRange &Range);
> +
> +public:
> + LocResolverBase(ASTContext &ctx, SourceLocation loc)
> + : Ctx(ctx), Loc(loc), Dcl(0), Stm(0), PassedLoc(0) {}
> +
> + /// \brief We found a AST node that corresponds to the source
> location.
> + bool FoundIt() const { return Dcl != 0 || Stm != 0; }
> +
> + /// \brief We either found a AST node or we passed the source
> location while
> + /// searching.
> + bool Finished() const { return FoundIt() || PassedLoc; }
> +
> + Decl *getDecl() const { return Dcl; }
> + Stmt *getStmt() const { return Stm; }
> +
> + getResult() const {
> + return std::make_pair(getDecl(), getStmt());
> + }
> +
> + /// \brief Debugging output.
> + void print(Decl *D);
> + /// \brief Debugging output.
> + void print(Stmt *Node);
> +};
> +
> +/// \brief Searches a statement for the AST node that corresponds
> to a source
> +/// location.
> +class VISIBILITY_HIDDEN StmtLocResolver : public LocResolverBase,
> + public
> StmtVisitor<StmtLocResolver> {
> +public:
> + StmtLocResolver(ASTContext &ctx, SourceLocation loc)
> + : LocResolverBase(ctx, loc) {}
> +
> + void VisitDeclStmt(DeclStmt *Node);
> + void VisitStmt(Stmt *Node);
> +};
> +
> +/// \brief Searches a declaration for the AST node that corresponds
> to a source
> +/// location.
> +class VISIBILITY_HIDDEN DeclLocResolver : public LocResolverBase,
> + public
> DeclVisitor<DeclLocResolver> {
> +public:
> + DeclLocResolver(ASTContext &ctx, SourceLocation loc)
> + : LocResolverBase(ctx, loc) {}
> +
> + void VisitDeclContext(DeclContext *DC);
> + void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
> + void VisitVarDecl(VarDecl *D);
> + void VisitFunctionDecl(FunctionDecl *D);
> + void VisitDecl(Decl *D);
> +};
> +
> +} // anonymous namespace
> +
> +void StmtLocResolver::VisitDeclStmt(DeclStmt *Node) {
> + CheckRange(Node);
> + if (!FoundIt())
> + return;
> + assert(Stm == Node && "Result not updated ?");
> +
> + // Search all declarations of this DeclStmt. If we found the one
> corresponding
> + // to the source location, update this StmtLocResolver's result.
> + DeclLocResolver DLR(Ctx, Loc);
> + for (DeclStmt::decl_iterator
> + I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) {
> + DLR.Visit(*I);
> + if (DLR.Finished()) {
> + if (DLR.FoundIt())
> + llvm::tie(Dcl, Stm) = DLR.getResult();
> + return;
> + }
> + }
> +}
> +
> +void StmtLocResolver::VisitStmt(Stmt *Node) {
> + CheckRange(Node);
> + if (!FoundIt())
> + return;
> + assert(Stm == Node && "Result not updated ?");
> +
> + // Search the child statements.
> + StmtLocResolver SLR(Ctx, Loc);
> + for (Stmt::child_iterator
> + I = Node->child_begin(), E = Node->child_end(); I != E; +
> +I) {
> + SLR.Visit(*I);
> + if (!SLR.Finished())
> + continue;
> +
> + // We either found it or we passed the source location.
> +
> + if (SLR.FoundIt()) {
> + // Only update Dcl if we found another more immediate
> 'parent' Decl for
> + // the statement.
> + if (SLR.getDecl())
> + Dcl = SLR.getDecl();
> + Stm = SLR.getStmt();
> + }
> +
> + return;
> + }
> +}
Okay, so the scheme here is: check whether the source location we're
looking for is within the range of the current node. If so, recurse to
find which sub-node it is in. I like that, although the CheckRange/
FoundIt/Finished trio feels more complicated that it needs to be,
because there's a lot of state encoded in Dcl/Stm/PassedLoc. Why not
just have your Visit functions return std::pair<Decl*, Stmt*> (or
something like it?).
> +void DeclLocResolver::VisitDeclContext(DeclContext *DC) {
> + DeclLocResolver DLR(Ctx, Loc);
> + for (DeclContext::decl_iterator
> + I = DC->decls_begin(Ctx), E = DC->decls_end(Ctx); I != E; +
> +I) {
> + DLR.Visit(*I);
> + if (DLR.Finished()) {
> + if (DLR.FoundIt())
> + llvm::tie(Dcl, Stm) = DLR.getResult();
> + return;
> + }
> + }
> +}
> +
> +void DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl
> *TU) {
> + VisitDeclContext(TU);
> +}
> +
> +void DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
> + CheckRange(D);
> + if (!FoundIt())
> + return;
> + assert(Dcl == D && "Result not updated ?");
> +
> + // First, search through the parameters of the function.
> + DeclLocResolver ParmRes(Ctx, Loc);
> + for (FunctionDecl::param_iterator
> + I = D->param_begin(), E = D->param_end(); I != E; ++I) {
> + ParmRes.Visit(*I);
> + if (ParmRes.Finished()) {
> + if (ParmRes.FoundIt())
> + llvm::tie(Dcl, Stm) = ParmRes.getResult();
> + return;
> + }
> + }
Okay, looks good.
> + // We didn't found the location in the parameters and we didn't
> get passed it.
> +
> + // Second, search through the declarations that are part of the
> function.
> + // If we find he location there, we won't have to search through
> its body.
> + DeclLocResolver DLR(Ctx, Loc);
> + DLR.VisitDeclContext(D);
> + if (DLR.FoundIt()) {
> + llvm::tie(Dcl, Stm) = DLR.getResult();
> + return;
> + }
> +
> + // We didn't find a declaration that corresponds to the source
> location.
> +
> + // Finally, search through the body of the function.
> + if (D->isThisDeclarationADefinition()) {
> + StmtLocResolver SLR(Ctx, Loc);
> + SLR.Visit(D->getBody(Ctx));
> + if (SLR.FoundIt()) {
> + llvm::tie(Dcl, Stm) = SLR.getResult();
> + // If we didn't find a more immediate 'parent' declaration
> for the
> + // statement, set the function as the parent.
> + if (Dcl == 0)
> + Dcl = D;
> + }
> + }
> +}
> +
> +void DeclLocResolver::VisitVarDecl(VarDecl *D) {
> + CheckRange(D);
> + if (!FoundIt())
> + return;
> + assert(Dcl == D && "Result not updated ?");
> +
> + // Check whether the location points to the init expression.
> + if (D->getInit()) {
> + StmtLocResolver SLR(Ctx, Loc);
> + SLR.Visit(D->getInit());
> + Stm = SLR.getStmt();
> + }
> +}
> +
> +void DeclLocResolver::VisitDecl(Decl *D) {
> + CheckRange(D);
> +}
> +
> +void LocResolverBase::CheckRange(Decl *D) {
> + SourceRange Range = D->getSourceRange();
> + if (!Range.isValid())
> + return;
> +
> + FixRange(Range);
> +
> + SourceManager &SourceMgr = Ctx.getSourceManager();
> + if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
> + return;
> +
> + if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
> + PassedLoc = true;
> + else
> + Dcl = D;
> +}
> +
> +void LocResolverBase::CheckRange(Stmt *Node) {
> + SourceRange Range = Node->getSourceRange();
> + if (!Range.isValid())
> + return;
> +
> + FixRange(Range);
> +
> + SourceManager &SourceMgr = Ctx.getSourceManager();
> + if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
> + return;
> +
> + if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
> + PassedLoc = true;
> + else
> + Stm = Node;
> +}
> +
> +void LocResolverBase::FixRange(SourceRange &Range) {
> + if (!Range.isValid())
> + return;
> +
> + unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
> + Ctx.getSourceManager
> (),
> + Ctx.getLangOptions());
> + Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1));
> +}
> +
> +void LocResolverBase::print(Decl *D) {
> + llvm::raw_ostream &OS = llvm::outs();
> + OS << "#### DECL ####\n";
> + D->print(OS, Ctx);
> + OS << " <";
> + D->getLocStart().print(OS, Ctx.getSourceManager());
> + OS << " > - <";
> + D->getLocEnd().print(OS, Ctx.getSourceManager());
> + OS << ">\n\n";
> + OS.flush();
> +}
> +
> +void LocResolverBase::print(Stmt *Node) {
> + llvm::raw_ostream &OS = llvm::outs();
> + OS << "#### STMT ####\n";
> + Node->printPretty(OS, Ctx);
> + OS << " <";
> + Node->getLocStart().print(OS, Ctx.getSourceManager());
> + OS << " > - <";
> + Node->getLocEnd().print(OS, Ctx.getSourceManager());
> + OS << ">\n\n";
> + OS.flush();
> +}
> +
> +
> +/// \brief Returns the AST node that a source location points to.
> +///
> +std::pair<Decl *, Stmt *>
> +clang::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) {
> + if (Loc.isInvalid())
> + return std::make_pair((Decl*)0, (Stmt*)0);
> +
> + DeclLocResolver DLR(Ctx, Loc);
> + DLR.Visit(Ctx.getTranslationUnitDecl());
> + return DLR.getResult();
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list