Path: blob/main/contrib/llvm-project/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp
35295 views
//===--- USRFinder.cpp - Clang refactoring library ------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file Implements a recursive AST visitor that finds the USR of a symbol at a9/// point.10///11//===----------------------------------------------------------------------===//1213#include "clang/Tooling/Refactoring/Rename/USRFinder.h"14#include "clang/AST/AST.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#include "llvm/ADT/SmallVector.h"2223using namespace llvm;2425namespace clang {26namespace tooling {2728namespace {2930/// Recursively visits each AST node to find the symbol underneath the cursor.31class NamedDeclOccurrenceFindingVisitor32: public RecursiveSymbolVisitor<NamedDeclOccurrenceFindingVisitor> {33public:34// Finds the NamedDecl at a point in the source.35// \param Point the location in the source to search for the NamedDecl.36explicit NamedDeclOccurrenceFindingVisitor(const SourceLocation Point,37const ASTContext &Context)38: RecursiveSymbolVisitor(Context.getSourceManager(),39Context.getLangOpts()),40Point(Point), Context(Context) {}4142bool visitSymbolOccurrence(const NamedDecl *ND,43ArrayRef<SourceRange> NameRanges) {44if (!ND)45return true;46for (const auto &Range : NameRanges) {47SourceLocation Start = Range.getBegin();48SourceLocation End = Range.getEnd();49if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||50!End.isFileID() || !isPointWithin(Start, End))51return true;52}53Result = ND;54return false;55}5657const NamedDecl *getNamedDecl() const { return Result; }5859private:60// Determines if the Point is within Start and End.61bool isPointWithin(const SourceLocation Start, const SourceLocation End) {62// FIXME: Add tests for Point == End.63return Point == Start || Point == End ||64(Context.getSourceManager().isBeforeInTranslationUnit(Start,65Point) &&66Context.getSourceManager().isBeforeInTranslationUnit(Point, End));67}6869const NamedDecl *Result = nullptr;70const SourceLocation Point; // The location to find the NamedDecl.71const ASTContext &Context;72};7374} // end anonymous namespace7576const NamedDecl *getNamedDeclAt(const ASTContext &Context,77const SourceLocation Point) {78const SourceManager &SM = Context.getSourceManager();79NamedDeclOccurrenceFindingVisitor Visitor(Point, Context);8081// Try to be clever about pruning down the number of top-level declarations we82// see. If both start and end is either before or after the point we're83// looking for the point cannot be inside of this decl. Don't even look at it.84for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {85SourceLocation StartLoc = CurrDecl->getBeginLoc();86SourceLocation EndLoc = CurrDecl->getEndLoc();87if (StartLoc.isValid() && EndLoc.isValid() &&88SM.isBeforeInTranslationUnit(StartLoc, Point) !=89SM.isBeforeInTranslationUnit(EndLoc, Point))90Visitor.TraverseDecl(CurrDecl);91}9293return Visitor.getNamedDecl();94}9596namespace {9798/// Recursively visits each NamedDecl node to find the declaration with a99/// specific name.100class NamedDeclFindingVisitor101: public RecursiveASTVisitor<NamedDeclFindingVisitor> {102public:103explicit NamedDeclFindingVisitor(StringRef Name) : Name(Name) {}104105// We don't have to traverse the uses to find some declaration with a106// specific name, so just visit the named declarations.107bool VisitNamedDecl(const NamedDecl *ND) {108if (!ND)109return true;110// Fully qualified name is used to find the declaration.111if (Name != ND->getQualifiedNameAsString() &&112Name != "::" + ND->getQualifiedNameAsString())113return true;114Result = ND;115return false;116}117118const NamedDecl *getNamedDecl() const { return Result; }119120private:121const NamedDecl *Result = nullptr;122StringRef Name;123};124125} // end anonymous namespace126127const NamedDecl *getNamedDeclFor(const ASTContext &Context,128const std::string &Name) {129NamedDeclFindingVisitor Visitor(Name);130Visitor.TraverseDecl(Context.getTranslationUnitDecl());131return Visitor.getNamedDecl();132}133134std::string getUSRForDecl(const Decl *Decl) {135llvm::SmallString<128> Buff;136137// FIXME: Add test for the nullptr case.138if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))139return "";140141return std::string(Buff);142}143144} // end namespace tooling145} // end namespace clang146147148