llvm/clang-tools-extra/clangd/FindTarget.h

//===--- FindTarget.h - What does an AST node refer to? ---------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Many clangd features are concerned with references in the AST:
//  - xrefs, go-to-definition, explicitly talk about references
//  - hover and code actions relate to things you "target" in the editor
//  - refactoring actions need to know about entities that are referenced
//    to determine whether/how the edit can be applied.
//
// Historically, we have used libIndex (IndexDataConsumer) to tie source
// locations to referenced declarations. This file defines a more decoupled
// approach based around AST nodes (DynTypedNode), and can be combined with
// SelectionTree or other traversals.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FINDTARGET_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FINDTARGET_H

#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Stmt.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/raw_ostream.h"

#include <bitset>

namespace clang {
namespace clangd {
class HeuristicResolver;

/// Describes the link between an AST node and a Decl it refers to.
enum class DeclRelation : unsigned;
/// A bitfield of DeclRelations.
class DeclRelationSet;

/// targetDecl() finds the declaration referred to by an AST node.
/// For example a RecordTypeLoc refers to the RecordDecl for the type.
///
/// In some cases there are multiple results, e.g. a dependent unresolved
/// OverloadExpr may have several candidates. All will be returned:
///
///    void foo(int);    <-- candidate
///    void foo(double); <-- candidate
///    template <typename T> callFoo() { foo(T()); }
///                                      ^ OverloadExpr
///
/// In other cases, there may be choices about what "referred to" means.
/// e.g. does naming a typedef refer to the underlying type?
/// The results are marked with a set of DeclRelations, and can be filtered.
///
///    struct S{};    <-- candidate (underlying)
///    using T = S{}; <-- candidate (alias)
///    T x;
///    ^ TypedefTypeLoc
///
/// Formally, we walk a graph starting at the provided node, and return the
/// decls that were found. Certain edges in the graph have labels, and for each
/// decl we return the set of labels seen on a path to the decl.
/// For the previous example:
///
///                TypedefTypeLoc T
///                       |
///                 TypedefType T
///                    /     \
///           [underlying]  [alias]
///                  /         \
///          RecordDecl S    TypeAliasDecl T
///
/// Note that this function only returns NamedDecls. Generally other decls
/// don't have references in this sense, just the node itself.
/// If callers want to support such decls, they should cast the node directly.
///
/// FIXME: some AST nodes cannot be DynTypedNodes, these cannot be specified.
llvm::SmallVector<const NamedDecl *, 1>
targetDecl(const DynTypedNode &, DeclRelationSet Mask,
           const HeuristicResolver *Resolver);

/// Similar to targetDecl(), however instead of applying a filter, all possible
/// decls are returned along with their DeclRelationSets.
/// This is suitable for indexing, where everything is recorded and filtering
/// is applied later.
llvm::SmallVector<std::pair<const NamedDecl *, DeclRelationSet>, 1>
allTargetDecls(const DynTypedNode &, const HeuristicResolver *);

enum class DeclRelation : unsigned {};
llvm::raw_ostream &operator<<(llvm::raw_ostream &, DeclRelation);

/// Information about a reference written in the source code, independent of the
/// actual AST node that this reference lives in.
/// Useful for tools that are source-aware, e.g. refactorings.
struct ReferenceLoc {};
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ReferenceLoc R);

/// Recursively traverse \p S and report all references explicitly written in
/// the code. The main use-case is refactorings that need to process all
/// references in some subrange of the file and apply simple edits, e.g. add
/// qualifiers.
/// FIXME: currently this does not report references to overloaded operators.
/// FIXME: extend to report location information about declaration names too.
void findExplicitReferences(const Stmt *S,
                            llvm::function_ref<void(ReferenceLoc)> Out,
                            const HeuristicResolver *Resolver);
void findExplicitReferences(const Decl *D,
                            llvm::function_ref<void(ReferenceLoc)> Out,
                            const HeuristicResolver *Resolver);
void findExplicitReferences(const ASTContext &AST,
                            llvm::function_ref<void(ReferenceLoc)> Out,
                            const HeuristicResolver *Resolver);

/// Find declarations explicitly referenced in the source code defined by \p N.
/// For templates, will prefer to return a template instantiation whenever
/// possible. However, can also return a template pattern if the specialization
/// cannot be picked, e.g. in dependent code or when there is no corresponding
/// Decl for a template instantiation, e.g. for templated using decls:
///    template <class T> using Ptr = T*;
///    Ptr<int> x;
///    ^~~ there is no Decl for 'Ptr<int>', so we return the template pattern.
/// \p Mask should not contain TemplatePattern or TemplateInstantiation.
llvm::SmallVector<const NamedDecl *, 1>
explicitReferenceTargets(DynTypedNode N, DeclRelationSet Mask,
                         const HeuristicResolver *Resolver);

// Boring implementation details of bitfield.

class DeclRelationSet {};
// The above operators can't be looked up if both sides are enums.
// over.match.oper.html#3.2
inline DeclRelationSet operator|(DeclRelation L, DeclRelation R) {}
inline DeclRelationSet operator&(DeclRelation L, DeclRelation R) {}
inline DeclRelationSet operator~(DeclRelation R) {}
llvm::raw_ostream &operator<<(llvm::raw_ostream &, DeclRelationSet);

} // namespace clangd
} // namespace clang

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_FINDTARGET_H