[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