summaryrefslogtreecommitdiffstats
path: root/clangd/URI.h
blob: cbde008b88617dc7d0913247051814519154f2a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//===--- URI.h - File URIs with schemes --------------------------*- C++-*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_PATHURI_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_PATHURI_H

#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Registry.h"

namespace clang {
namespace clangd {

/// A URI describes the location of a source file.
/// In the simplest case, this is a "file" URI that directly encodes the
/// absolute path to a file. More abstract cases are possible: a shared index
/// service might expose repo:// URIs that are relative to the source control
/// root.
///
/// Clangd handles URIs of the form <scheme>:[//<authority>]<body>. It doesn't
/// further split the authority or body into constituent parts (e.g. query
/// strings is included in the body).
class URI {
public:
  URI(llvm::StringRef Scheme, llvm::StringRef Authority, llvm::StringRef Body);

  /// Returns decoded scheme e.g. "https"
  llvm::StringRef scheme() const { return Scheme; }
  /// Returns decoded authority e.g. "reviews.lvm.org"
  llvm::StringRef authority() const { return Authority; }
  /// Returns decoded body e.g. "/D41946"
  llvm::StringRef body() const { return Body; }

  /// Returns a string URI with all components percent-encoded.
  std::string toString() const;

  /// Creates a URI for a file in the given scheme. \p Scheme must be
  /// registered. The URI is percent-encoded.
  static llvm::Expected<URI> create(llvm::StringRef AbsolutePath,
                                    llvm::StringRef Scheme);

  // Similar to above except this picks a registered scheme that works. If none
  // works, this falls back to "file" scheme.
  static URI create(llvm::StringRef AbsolutePath);

  /// This creates a file:// URI for \p AbsolutePath. The path must be absolute.
  static URI createFile(llvm::StringRef AbsolutePath);

  /// Parse a URI string "<scheme>:[//<authority>/]<path>". Percent-encoded
  /// characters in the URI will be decoded.
  static llvm::Expected<URI> parse(llvm::StringRef Uri);

  /// Resolves the absolute path of \p U. If there is no matching scheme, or the
  /// URI is invalid in the scheme, this returns an error.
  ///
  /// \p HintPath A related path, such as the current file or working directory,
  /// which can help disambiguate when the same file exists in many workspaces.
  static llvm::Expected<std::string> resolve(const URI &U,
                                             llvm::StringRef HintPath = "");

  /// Resolves \p AbsPath into a canonical path of its URI, by converting
  /// \p AbsPath to URI and resolving the URI to get th canonical path.
  /// This ensures that paths with the same URI are resolved into consistent
  /// file path.
  static llvm::Expected<std::string> resolvePath(llvm::StringRef AbsPath,
                                                 llvm::StringRef HintPath = "");

  /// Gets the preferred spelling of this file for #include, if there is one,
  /// e.g. <system_header.h>, "path/to/x.h".
  ///
  /// This allows URI schemas to provide their customized include paths.
  ///
  /// Returns an empty string if normal include-shortening based on the absolute
  /// path should be used.
  /// Fails if the URI is not valid in the schema.
  static llvm::Expected<std::string> includeSpelling(const URI &U);

  friend bool operator==(const URI &LHS, const URI &RHS) {
    return std::tie(LHS.Scheme, LHS.Authority, LHS.Body) ==
           std::tie(RHS.Scheme, RHS.Authority, RHS.Body);
  }

  friend bool operator<(const URI &LHS, const URI &RHS) {
    return std::tie(LHS.Scheme, LHS.Authority, LHS.Body) <
           std::tie(RHS.Scheme, RHS.Authority, RHS.Body);
  }

private:
  URI() = default;

  std::string Scheme;
  std::string Authority;
  std::string Body;
};

/// URIScheme is an extension point for teaching clangd to recognize a custom
/// URI scheme. This is expected to be implemented and exposed via the
/// URISchemeRegistry.
class URIScheme {
public:
  virtual ~URIScheme() = default;

  /// Returns the absolute path of the file corresponding to the URI
  /// authority+body in the file system. See URI::resolve for semantics of
  /// \p HintPath.
  virtual llvm::Expected<std::string>
  getAbsolutePath(llvm::StringRef Authority, llvm::StringRef Body,
                  llvm::StringRef HintPath) const = 0;

  virtual llvm::Expected<URI>
  uriFromAbsolutePath(llvm::StringRef AbsolutePath) const = 0;

  /// Returns the include path of the file (e.g. <path>, "path"), which can be
  /// #included directly. See URI::includeSpelling for details.
  virtual llvm::Expected<std::string> getIncludeSpelling(const URI &U) const {
    return ""; // no customized include path for this scheme.
  }
};

/// By default, a "file" scheme is supported where URI paths are always absolute
/// in the file system.
typedef llvm::Registry<URIScheme> URISchemeRegistry;

} // namespace clangd
} // namespace clang

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_PATHURI_H