brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.9 KiB · 91d5caf Raw
145 lines · cpp
1//===--- USRFinder.cpp - Clang refactoring library ------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file Implements a recursive AST visitor that finds the USR of a symbol at a10/// point.11///12//===----------------------------------------------------------------------===//13 14#include "clang/Tooling/Refactoring/Rename/USRFinder.h"15#include "clang/AST/ASTContext.h"16#include "clang/AST/RecursiveASTVisitor.h"17#include "clang/Basic/SourceManager.h"18#include "clang/Index/USRGeneration.h"19#include "clang/Lex/Lexer.h"20#include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h"21 22using namespace llvm;23 24namespace clang {25namespace tooling {26 27namespace {28 29/// Recursively visits each AST node to find the symbol underneath the cursor.30class NamedDeclOccurrenceFindingVisitor31    : public RecursiveSymbolVisitor<NamedDeclOccurrenceFindingVisitor> {32public:33  // Finds the NamedDecl at a point in the source.34  // \param Point the location in the source to search for the NamedDecl.35  explicit NamedDeclOccurrenceFindingVisitor(const SourceLocation Point,36                                             const ASTContext &Context)37      : RecursiveSymbolVisitor(Context.getSourceManager(),38                               Context.getLangOpts()),39        Point(Point), Context(Context) {}40 41  bool visitSymbolOccurrence(const NamedDecl *ND,42                             ArrayRef<SourceRange> NameRanges) {43    if (!ND)44      return true;45    for (const auto &Range : NameRanges) {46      SourceLocation Start = Range.getBegin();47      SourceLocation End = Range.getEnd();48      if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||49          !End.isFileID() || !isPointWithin(Start, End))50        return true;51    }52    Result = ND;53    return false;54  }55 56  const NamedDecl *getNamedDecl() const { return Result; }57 58private:59  // Determines if the Point is within Start and End.60  bool isPointWithin(const SourceLocation Start, const SourceLocation End) {61    // FIXME: Add tests for Point == End.62    return Point == Start || Point == End ||63           (Context.getSourceManager().isBeforeInTranslationUnit(Start,64                                                                 Point) &&65            Context.getSourceManager().isBeforeInTranslationUnit(Point, End));66  }67 68  const NamedDecl *Result = nullptr;69  const SourceLocation Point; // The location to find the NamedDecl.70  const ASTContext &Context;71};72 73} // end anonymous namespace74 75const NamedDecl *getNamedDeclAt(const ASTContext &Context,76                                const SourceLocation Point) {77  const SourceManager &SM = Context.getSourceManager();78  NamedDeclOccurrenceFindingVisitor Visitor(Point, Context);79 80  // Try to be clever about pruning down the number of top-level declarations we81  // see. If both start and end is either before or after the point we're82  // looking for the point cannot be inside of this decl. Don't even look at it.83  for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {84    SourceLocation StartLoc = CurrDecl->getBeginLoc();85    SourceLocation EndLoc = CurrDecl->getEndLoc();86    if (StartLoc.isValid() && EndLoc.isValid() &&87        SM.isBeforeInTranslationUnit(StartLoc, Point) !=88            SM.isBeforeInTranslationUnit(EndLoc, Point))89      Visitor.TraverseDecl(CurrDecl);90  }91 92  return Visitor.getNamedDecl();93}94 95namespace {96 97/// Recursively visits each NamedDecl node to find the declaration with a98/// specific name.99class NamedDeclFindingVisitor100    : public RecursiveASTVisitor<NamedDeclFindingVisitor> {101public:102  explicit NamedDeclFindingVisitor(StringRef Name) : Name(Name) {}103 104  // We don't have to traverse the uses to find some declaration with a105  // specific name, so just visit the named declarations.106  bool VisitNamedDecl(const NamedDecl *ND) {107    if (!ND)108      return true;109    // Fully qualified name is used to find the declaration.110    if (Name != ND->getQualifiedNameAsString() &&111        Name != "::" + ND->getQualifiedNameAsString())112      return true;113    Result = ND;114    return false;115  }116 117  const NamedDecl *getNamedDecl() const { return Result; }118 119private:120  const NamedDecl *Result = nullptr;121  StringRef Name;122};123 124} // end anonymous namespace125 126const NamedDecl *getNamedDeclFor(const ASTContext &Context,127                                 const std::string &Name) {128  NamedDeclFindingVisitor Visitor(Name);129  Visitor.TraverseDecl(Context.getTranslationUnitDecl());130  return Visitor.getNamedDecl();131}132 133std::string getUSRForDecl(const Decl *Decl) {134  llvm::SmallString<128> Buff;135 136  // FIXME: Add test for the nullptr case.137  if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))138    return "";139 140  return std::string(Buff);141}142 143} // end namespace tooling144} // end namespace clang145