├── .clang-format
├── .clang-tidy
├── .gitignore
├── CMakeLists.txt
├── CPPLINT.cfg
├── LICENSE
├── README.md
├── clang-expand.cpp
├── cmake
└── modules
│ └── FindLLVM.cmake
├── docker-compose.yaml
├── docker
├── .dockerignore
├── build.sh
├── debian.Dockerfile
├── fedora.Dockerfile
├── opensuse.Dockerfile
└── ubuntu.Dockerfile
├── docs
└── Doxyfile
├── extra
└── clang-expand.gif
├── include
└── clang-expand
│ ├── common
│ ├── assignee-data.hpp
│ ├── call-data.hpp
│ ├── canonical-location.hpp
│ ├── context-data.hpp
│ ├── declaration-data.hpp
│ ├── definition-data.hpp
│ ├── definition-rewriter.hpp
│ ├── location.hpp
│ ├── offset.hpp
│ ├── query.hpp
│ ├── range.hpp
│ └── routines.hpp
│ ├── definition-search
│ ├── action.hpp
│ ├── consumer.hpp
│ ├── match-handler.hpp
│ └── tool-factory.hpp
│ ├── options.hpp
│ ├── result.hpp
│ ├── search.hpp
│ └── symbol-search
│ ├── action.hpp
│ ├── consumer.hpp
│ ├── macro-search.hpp
│ ├── match-handler.hpp
│ └── tool-factory.hpp
├── source
├── CMakeLists.txt
├── common
│ ├── assignee-data.cpp
│ ├── call-data.cpp
│ ├── canonical-location.cpp
│ ├── declaration-data.cpp
│ ├── definition-data.cpp
│ ├── definition-rewriter.cpp
│ ├── location.cpp
│ ├── offset.cpp
│ ├── range.cpp
│ └── routines.cpp
├── definition-search
│ ├── action.cpp
│ ├── consumer.cpp
│ ├── match-handler.cpp
│ └── tool-factory.cpp
├── result.cpp
├── search.cpp
└── symbol-search
│ ├── action.cpp
│ ├── consumer.cpp
│ ├── macro-search.cpp
│ ├── match-handler.cpp
│ └── tool-factory.cpp
└── third-party
└── json.hpp
/.clang-format:
--------------------------------------------------------------------------------
1 | Language: Cpp
2 | Standard: Cpp11
3 | BasedOnStyle: Google
4 |
5 | AllowAllParametersOfDeclarationOnNextLine: true
6 | AllowShortBlocksOnASingleLine: false
7 | AllowShortCaseLabelsOnASingleLine: true
8 | AllowShortFunctionsOnASingleLine: false
9 | AllowShortIfStatementsOnASingleLine: true
10 | AllowShortLoopsOnASingleLine: true
11 |
12 | AlignOperands: true
13 | AlignConsecutiveAssignments: false
14 |
15 | BinPackArguments: false
16 | BinPackParameters: false
17 | BreakConstructorInitializersBeforeComma: true
18 | ColumnLimit: 80
19 | ConstructorInitializerAllOnOneLineOrOnePerLine: true
20 | ConstructorInitializerIndentWidth: 0
21 | ContinuationIndentWidth: 4
22 | Cpp11BracedListStyle: true
23 | DerivePointerAlignment: false
24 | IndentCaseLabels: true
25 | IndentWidth: 2
26 | MaxEmptyLinesToKeep: 2
27 | NamespaceIndentation: None
28 | PointerAlignment: Left
29 | SpacesBeforeTrailingComments: 2
30 | TabWidth: 2
31 | UseTab: Never
32 |
33 | PenaltyExcessCharacter: 1000000
34 | PenaltyReturnTypeOnItsOwnLine: 100
35 | PenaltyBreakBeforeFirstCallParameter: 10000
36 |
--------------------------------------------------------------------------------
/.clang-tidy:
--------------------------------------------------------------------------------
1 | ---
2 | # Note: there must be no spaces before the '-', so put the comma first.
3 | Checks: '
4 | *
5 | ,-google-runtime-references
6 | ,-llvm-namespace-comment
7 | ,-google-readability-namespace-comments
8 | ,-readability-braces-around-statements
9 | ,-readability-implicit-bool-cast
10 | ,-cppcoreguidelines-pro-bounds-array-to-pointer-decay
11 | ,-llvm-include-order
12 | ,-readability-named-parameter
13 | ' # End Checks
14 |
15 | WarningsAsErrors: ''
16 | HeaderFilterRegex: 'include/clang-expand/.*'
17 | ...
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Own
2 | *.dSYM
3 | build/
4 | .clang_complete
5 | docs/html/
6 | bin/
7 |
8 | # Created by https://www.gitignore.io/api/c++,emacs
9 |
10 | ### C++ ###
11 | # Prerequisites
12 | *.d
13 |
14 | # Compiled Object files
15 | *.slo
16 | *.lo
17 | *.o
18 | *.obj
19 |
20 | # Precompiled Headers
21 | *.gch
22 | *.pch
23 |
24 | # Compiled Dynamic libraries
25 | *.so
26 | *.dylib
27 | *.dll
28 |
29 | # Fortran module files
30 | *.mod
31 | *.smod
32 |
33 | # Compiled Static libraries
34 | *.lai
35 | *.la
36 | *.a
37 | *.lib
38 |
39 | # Executables
40 | *.exe
41 | *.out
42 | *.app
43 |
44 | ### Emacs ###
45 | # -*- mode: gitignore; -*-
46 | *~
47 | \#*\#
48 | /.emacs.desktop
49 | /.emacs.desktop.lock
50 | *.elc
51 | auto-save-list
52 | tramp
53 | .\#*
54 |
55 | # Org-mode
56 | .org-id-locations
57 | *_archive
58 |
59 | # flymake-mode
60 | *_flymake.*
61 |
62 | # eshell files
63 | /eshell/history
64 | /eshell/lastdir
65 |
66 | # elpa packages
67 | /elpa/
68 |
69 | # reftex files
70 | *.rel
71 |
72 | # AUCTeX auto folder
73 | /auto/
74 |
75 | # cask packages
76 | .cask/
77 | dist/
78 |
79 | # Flycheck
80 | flycheck_*.el
81 |
82 | # server auth directory
83 | /server/
84 |
85 | # projectiles files
86 | .projectile
87 |
88 | # directory configuration
89 | .dir-locals.el
90 |
91 | # End of https://www.gitignore.io/api/c++,emacs
92 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | ###########################################################
2 | ## CMAKE SETUP
3 | ###########################################################
4 |
5 | cmake_minimum_required(VERSION 3.5)
6 | project(clang-expand)
7 |
8 | ###########################################################
9 | ## DOCUMENTATION
10 | ###########################################################
11 |
12 | # Add a target to generate documentation with Doxygen.
13 | find_package(Doxygen)
14 | if(DOXYGEN_FOUND)
15 | # Replace all variables of the form @@ inside the Doxyfile
16 | configure_file(
17 | ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile
18 | ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY
19 | )
20 | add_custom_target(
21 | docs
22 | ${DOXYGEN_EXECUTABLE}
23 | ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
24 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/docs
25 | COMMENT "Generating API documentation with Doxygen" VERBATIM
26 | )
27 | endif()
28 |
29 | ###########################################################
30 | ## DEPENDENCIES
31 | ###########################################################
32 |
33 | set(CMAKE_MODULE_PATH
34 | ${CMAKE_MODULE_PATH}
35 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/")
36 |
37 | set(CLANG_LIBS
38 | clangAST
39 | clangASTMatchers
40 | clangAnalysis
41 | clangBasic
42 | clangDriver
43 | clangEdit
44 | clangFrontend
45 | clangFrontendTool
46 | clangLex
47 | clangParse
48 | clangSema
49 | clangEdit
50 | clangRewrite
51 | clangRewriteFrontend
52 | clangSerialization
53 | clangTooling
54 | clangToolingCore
55 | )
56 |
57 | if (NOT CMAKE_HOST_APPLE)
58 | set(CLANG_LIBS -Wl,--start-group ${CLANG_LIBS} -Wl,--end-group)
59 | endif()
60 |
61 | find_package(LLVM REQUIRED)
62 |
63 | include_directories(SYSTEM ${LLVM_INCLUDE_DIRS})
64 | include_directories(SYSTEM ${CLANG_INCLUDE_DIRS})
65 |
66 | # Third Party
67 | include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR})
68 |
69 | # Also contains clang libraries
70 | link_directories(${LLVM_LIBRARY_DIRS})
71 | set(CMAKE_EXE_LINKER_FLAGS ${LLVM_LD_FLAGS_STRING})
72 |
73 | ###########################################################
74 | ## COMPILER FLAGS
75 | ###########################################################
76 |
77 | set(CXX_STANDARD_REQUIRED ON)
78 |
79 | list(REMOVE_ITEM LLVM_CXX_FLAGS
80 | ${LLVM_INCLUDE_DIRS} # Already included
81 | "-DNDEBUG"
82 | "-std=c++11" # Want our own standard
83 | "-std=c++1y"
84 | "-stdlib=libc++"
85 | "-fno-rtti-DLLVM_BUILD_GLOBAL_ISEL" # Weird bugs on Debian
86 | "-fdata-sections-O3"
87 | "-fdata-sections-O2")
88 |
89 | if (NOT ${CMAKE_CXX_COMPILER} MATCHES "clang.*")
90 | # These seem to be clang-specific
91 | list(REMOVE_ITEM LLVM_CXX_FLAGS
92 | "-Wcovered-switch-default"
93 | "-Wstring-conversion")
94 | endif()
95 |
96 | set(EXTRA_FLAGS
97 | -Os
98 | -O3
99 | -fdata-sections
100 | -std=c++14
101 | -fno-rtti
102 | -DLLVM_BUILD_GLOBAL_ISEL
103 | -DJSON_NOEXCEPTION)
104 | set(ALL_FLAGS ${WARNINGS} ${LLVM_CXX_FLAGS} ${EXTRA_FLAGS})
105 |
106 | add_compile_options(${ALL_FLAGS})
107 |
108 | ###########################################################
109 | ## INCLUDES
110 | ###########################################################
111 |
112 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
113 |
114 | ###########################################################
115 | ## SOURCES
116 | ###########################################################
117 |
118 | add_subdirectory(source)
119 |
120 | ###########################################################
121 | ## TARGETS
122 | ###########################################################
123 |
124 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
125 | ${CMAKE_BINARY_DIR}/bin/${CLANG_EXPAND_OS_NAME})
126 | message(STATUS "Binaries will land in ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
127 |
128 | add_executable(clang-expand clang-expand.cpp)
129 | target_link_libraries(clang-expand
130 | clang-expand-library
131 | ${CLANG_LIBS}
132 | ${LLVM_LIBS})
133 |
134 | ###########################################################
135 | ## DOCKER
136 | ###########################################################
137 |
138 | find_program(DOCKER_COMPOSE NAMES docker-compose)
139 | if (DOCKER_COMPOSE)
140 | message(STATUS "Found docker-compose at ${DOCKER_COMPOSE}")
141 | add_custom_target(
142 | docker
143 | COMMAND docker-compose up
144 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/
145 | COMMENT "Building clang-expand with docker" VERBATIM
146 | )
147 | message(STATUS "Enabled 'docker' target for building binaries")
148 | endif()
149 |
150 | ###########################################################
151 | ## TOOLS <3
152 | ###########################################################
153 |
154 | # IWYU
155 | option(CLANG_EXPAND_IWYU OFF)
156 |
157 | if(${CLANG_EXPAND_IWYU})
158 | find_program(iwyu_path NAMES include-what-you-use iwyu)
159 | if(iwyu_path)
160 | message(STATUS "Found include-what-you-use, integrating with target")
161 | set_property(TARGET clang-expand
162 | PROPERTY CXX_INCLUDE_WHAT_YOU_USE ${iwyu_path})
163 | else()
164 | message(WARNING "Could not find include-what-you-use, skipping")
165 | endif()
166 | endif()
167 |
--------------------------------------------------------------------------------
/CPPLINT.cfg:
--------------------------------------------------------------------------------
1 | # cpplint configuration
2 |
3 | filter=-build/include_order
4 | filter=-build/c++11
5 | filter=-legal/copyright
6 | filter=-runtime/references
7 | filter=-whitespace/operators
8 | filter=-whitespace/line_length
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2017 Peter Goldsborough
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of
5 | this software and associated documentation files (the "Software"), to deal in
6 | the Software without restriction, including without limitation the rights to
7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 | the Software, and to permit persons to whom the Software is furnished to do so,
9 | subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # :dragon: clang-expand
2 |
3 |
4 |
5 |
6 | A clang tool for happy refactoring without source-code gymnastics.
7 |
8 |
9 |
10 |
11 | ## Overview
12 |
13 | I recently overheard the following conversation on my way to work, that may seem familiar to you:
14 |
15 | > __Gandalf__: It is important to refactor your code and keep functions concise and coherent.
16 | > __Harry Potter__: Yeah, sure, but I hate having to jump around between files to get the full picture of what my code is doing. One function = one place to look.
17 | > __Obi Wan Kenobi__: Use the force, Harry.
18 | > __Batman__: He means *clang-expand* :sparkles:
19 |
20 | Inspired by Gandalf's words, I set out to find a solution to Harry's problem and
21 | built *clang-expand*. Point it at a function invocation in your source code and
22 | tell it where to look for stuff, and it will find the correct definition of that
23 | particular (template) function, method, operator overload or even constructor
24 | and "expand" it into the current scope. *Expanding* means it will:
25 |
26 | 1. Replace parameters with respective argument expressions. That is, for a
27 | function `f(int x)` that you call with `f(5)`, clang-expand will rewrite every
28 | occurrence of `x` inside `f` to `5`. Note that since clang-expand uses clang, it
29 | actually understands C++ and knows what occurrences of `x` are parameter
30 | references and what aren't. Default arguments are replaced as well.
31 |
32 |
33 |
34 | Given
35 |
36 | template<typename Range>
37 | void magic(Range& range, int meaning_of_life = 42) {
38 | auto iterator = std::find(range.begin(), range.end(), meaning_of_life);
39 | if (iterator != range.end()) {
40 | range.erase(iterator);
41 | std::cout << "Successfully erased all meaning of life\n";
42 | }
43 | }
44 |
45 | Unexpanded Expanded
46 |
47 |
48 | std::vector v = {1, 42, 3};
49 | magic(v);
50 | ^
51 |
52 |
53 | std::vector v = {1, 42, 3};
54 | auto iterator = std::find(v.begin(), v.end(), 42);
55 | if (iterator != v.end()) {
56 | std::cout << "Successfully erased all meaning of life\n";
57 | v.erase(iterator);
58 | }
59 |
60 |
61 |
62 |
63 |
64 | As you can see, clang-expand actually instantiated the template function during
65 | the expansion. This is because on the level that it operates on within the clang
66 | AST, semantic analysis, including template type deduction, are already complete.
67 | This means that calling templates is not a problem for clang-expand.
68 |
69 | 2. If you're assigning the return value of a function you expand to a
70 | variable, clang-expand will replace every `return` statement inside the function
71 | with an assignment. It attempts to do this in a reasonably intelligent way,
72 | constructing the variable with the return value directly if there is only one
73 | `return` and else first declaring the variable and then assigning. The latter
74 | only works if the type of the variable is default-constructible and clang-expand
75 | will refuse to expand otherwise.
76 |
77 |
78 | Given
79 |
80 | std::string concat(const std::string& first, const std::string& second) {
81 | return first + "-"s + second;
82 | }
83 |
84 | std::string concat(const std::string& first, const std::string& second, bool kebab) {
85 | if (kebab) {
86 | return first + "-"s + second;
87 | } else {
88 | return first + std::toupper(second.front(), {}) + second.substr(1);
89 | }
90 | }
91 |
92 | Unexpanded Expanded
93 |
94 |
95 | auto kebab = concat("clang", "expand");
96 | ^
97 |
98 |
99 | std::string kebab = "clang" + "-"s + "expand";
100 |
101 |
102 | Unexpanded Expanded
103 |
104 |
105 | auto maybeCamel = concat("clang", "expand", flipCoin());
106 | ^
107 |
108 |
109 | std::string maybeCamel;
110 | if (flipCoin()) {
111 | maybeCamel = "clang" + "-"s + "expand";
112 | } else {
113 | maybeCamel = "clang" + std::toupper("expand".front(), {}) + "expand".substr(1);
114 | }
115 |
116 |
117 |
118 |
119 | 3. If you're calling a method, clang-expand will prepend the base to every method or member of referenced inside:
120 |
121 |
122 | Unexpanded Expanded1
123 |
124 |
125 | std::vector my_vec;
126 | my_vec.emplace_back(42);
127 | ^
128 |
129 |
130 | std::vector my_vec;
131 | if (my_vec.__end_ < my_vec.__end_cap())
132 | {
133 | __RAII_IncreaseAnnotator __annotator(*this);
134 | __alloc_traits::construct(my_vec.__alloc(),
135 | _VSTD::__to_raw_pointer(my_vec.__end_),
136 | _VSTD::forward<_Args>(42)...);
137 | __annotator.__done();
138 | ++my_vec.__end_;
139 | }
140 | else
141 | my_vec.__emplace_back_slow_path(_VSTD::forward<_Args>(42)...);
142 |
143 |
144 |
145 |
146 | 1 *This is the implementation on my system, of course.*
147 |
148 | 4. If the function you're expanding is an operator, clang-expand can handle that just as well:
149 |
150 |
151 | Given
152 |
153 | struct by_lightning {
154 | bool operator==(const by_lightning& other) const noexcept {
155 | return this->circuit == other.circuit;
156 | }
157 | short circuit;
158 | };
159 |
160 | Unexpanded Expanded
161 |
162 |
163 | by_lightning first{1};
164 | by_lightning second{2};
165 | return first == second;
166 | ^
167 |
168 |
169 | by_lightning first{1};
170 | by_lightning second{2};
171 | return first.circuit == other.circuit;
172 |
173 |
174 |
175 |
176 | 5. Besides expanding functions that are real code, clang-expand can also expand
177 | function-like and *even object-like* macros (that just `#define` something
178 | without being parameterized):
179 |
180 |
181 | Given
182 |
183 | #define MAX(a, b) (a) > (b) ? (a) : (b)
184 | #define PI 3.14
185 |
186 | Unexpanded Expanded
187 |
188 |
189 | double pi_if_a_greater_b(double a, double b) {
190 | auto greater = MAX(a, b);
191 | ^
192 | if (greater == a) {
193 | return PI;
194 | ^
195 | }
196 | return -1;
197 | }
198 |
199 |
200 | double pi_if_a_greater_b(double a, double b) {
201 | auto greater = a > b ? a : b;
202 | if (greater == a) {
203 | return 3.14;
204 | }
205 | return -1;
206 | }
207 |
208 |
209 |
210 |
211 | 6. clang-expand not only performs substitution for function parameters, it can also substitute type and non-type template parameters! Voilà:
212 |
213 |
214 | Given
215 |
216 | template <typename Explicit, unsigned number, typename Deduced>
217 | auto my_template(Deduced deduced) {
218 | using Alias = Explicit;
219 | return deduced + static_cast<Alias>(number);
220 | }
221 |
222 | Unexpanded Expanded
223 |
224 |
225 | my_template<float, 24>(10);
226 | ^
227 |
228 |
229 | using Alias = float;
230 | return 10 + static_cast<Alias>(24);
231 |
232 |
233 |
234 |
235 | ## Usage
236 |
237 | clang-expand is implemented as a command-line tool targeted at building editor integrations. The tool itself has the following help text (excerpt):
238 |
239 | ```
240 | $ clang-expand -help
241 | USAGE: clang-expand [options] [... ]
242 |
243 | OPTIONS:
244 |
245 | clang-expand options:
246 |
247 | -call - Whether to return the source range of the call
248 | -column= - The column number of the function to expand
249 | -declaration - Whether to return the original declaration
250 | -definition - Whether to return the original definition
251 | -file= - The source file of the function to expand
252 | -line= - The line number of the function to expand
253 | -rewrite - Whether to generate the rewritten (expanded) definition
254 | ```
255 |
256 | Basically, you have to pass it any sources you want the tool to look for
257 | definitions in as positional arguments. The `-file`, `-line` and `-column`
258 | options then determine the location of the call to expand. This position has to
259 | be somewhere on the token you want to expand (i.e. not necessarily at the
260 | beginning). The `-file` defaults to the first source if you omit the option.
261 | Additionally, you have to pass any options required to compile the files at the
262 | end, following `--`. For example, given:
263 |
264 | `foo.h`:
265 | ```cpp
266 | int foo();
267 | ```
268 |
269 | `foo.cpp`:
270 | ```cpp
271 | int foo() { return 42; }
272 | ```
273 |
274 | `main.cpp`:
275 | ```cpp
276 | #include "foo.h"
277 | auto main() -> int {
278 | auto x = foo();
279 | }
280 | ```
281 |
282 | The following command would do the job:
283 |
284 | ```bash
285 | $ clang-expand main.cpp foo.cpp -line=3 -column=14 -- -I/path/to/include -std=c++14
286 | ```
287 |
288 | which will output:
289 |
290 | ```json
291 | {
292 | "call": {
293 | "begin": {
294 | "column": 3,
295 | "line": 3
296 | },
297 | "end": {
298 | "column": 17,
299 | "line": 3
300 | }
301 | },
302 | "declaration": {
303 | "location": {
304 | "filename": "/path/to/foo.h",
305 | "offset": {
306 | "column": 5,
307 | "line": 1
308 | }
309 | },
310 | "name": "foo",
311 | "text": "int foo();"
312 | },
313 | "definition": {
314 | "location": {
315 | "filename": "/path/to/foo.cpp",
316 | "offset": {
317 | "column": 5,
318 | "line": 1
319 | }
320 | },
321 | "macro": false,
322 | "rewritten": "int x = 42;",
323 | "text": "int foo() { return 42; }"
324 | }
325 | }
326 | ```
327 |
328 | Yes, JSON! But why so much output? Well, since clang-expand has to find the
329 | declaration and definition of a function you want to expand, it might as well
330 | also return the location and full text for either (because why not). As such,
331 | clang-expand can also be used as a backend for
332 | "go-to-definition"/"show-declaration" functions inside a text editor (though an
333 | indexed-solution like [ctags](https://en.wikipedia.org/wiki/Ctags) is likely
334 | faster for just that).
335 |
336 | For expanding, what's most interesting here is the `call` section and the
337 | `definition.rewritten` field. The former is the entire range (defined by two
338 | `(line, column)` pairs) in the source code that you'll want to replace with the
339 | expansion. The latter is the text to insert instead.
340 |
341 | Even though the overhead to grab information about the definition and
342 | declaration is negligible compared to the entire operation, it may still be
343 | beneficial to turn off retrieval of certain parts of what clang-expand outputs,
344 | or you may simply not need some of the output. This is the case when you're only
345 | interested in expanding for example, where you only need the `call` and
346 | `definition` section. For this reason, the clang-expand tool takes boolean
347 | `-call, -declaration, -definition` and `-rewrite` options. By default, these
348 | flags are all set to `true`, i.e. all of these sections will be included. By
349 | setting them to `-=false`, you can turn them off, however. For example:
350 |
351 | ```bash
352 | $ clang-expand main.cpp foo.cpp -line=3 -column=14 -declaration=false -definition=false -rewrite=false -- -I/path/to/include -std=c++14
353 | ```
354 |
355 | outputs only the call range:
356 |
357 | ```json
358 | {
359 | "call": {
360 | "begin": {
361 | "column": 3,
362 | "line": 3
363 | },
364 | "end": {
365 | "column": 17,
366 | "line": 3
367 | }
368 | }
369 | }
370 | ```
371 |
372 | ### Example editor integration
373 |
374 | As my preferred editor as of 23rd March 2017, 19:42 GMT is
375 | [Atom](http://atom.io), I have implemented an example editor integration of
376 | clang-expand for Atom:
377 | [atom-clang-expand](https://github.com/goldsborough/atom-clang-expand). My
378 | preferred editor may have changed by the end of the last sentence, so I may be
379 | working on an integration for another editor.
380 |
381 | I would be very happy to assist anyone in building an integration with Vim,
382 | Emacs, Sublime or any other editor, so please reach out if you would like to
383 | build one. Implementing just the expansion functionality is quite trivial, as
384 | you just need to invoke clang-expand, parse its output and replace some text. I
385 | have also implemented go-to-declaration/definition and
386 | show-declaration/definition for my Atom package, but those are optional (though
387 | arguably even easier to implement, as you just have to jump to another
388 | location or show some text).
389 |
390 | ## Limitations
391 |
392 | While clang-expand tries very hard to expand calls in way that produces
393 | syntactically correct code, this just simply is not always possible without
394 | impacting other features (such as readability of the expanded code). A simple
395 | example is when you have a function taking a parameter and you pass a variable
396 | called `x` as an argument. If `x` is already used for something else inside the
397 | function, there will be a collision. This can be detected in clang-expand -- no
398 | problem -- and solved by mangling the name somehow (e.g. appending `_expanded`).
399 | However, this reduces the readability of the produced expansion and is therefore
400 | not done. Note that this means clang-expand will generally not work well with
401 | recursive functions.
402 |
403 | The bottom line is that the produced code will not always be valid, but you'll
404 | most likely not care, since you probably just want to see what the code would
405 | look like "more or less". Nevertheless, this is something where clang-expand
406 | could be improved in the future.
407 |
408 | ## Building
409 |
410 | If you just want to use clang-expand, you can grab the executable from the
411 | [Release](https://github.com/goldsborough/clang-expand/releases) page.
412 |
413 | To build from source, clang-expand uses cmake and requires a C++14-capable compiler.
414 | It also depends on the full [LLVM](https://github.com/llvm-mirror/llvm) and
415 | [clang](https://github.com/llvm-mirror/clang) source, so you will need to download
416 | those, as explained [here](http://llvm.org/docs/GettingStarted.html#for-developers-to-work-with-a-git-monorepo).
417 | If you're a moral person, you'll compile a tool that starts with the word "clang" with the aptly
418 | named compiler. However, we do have support for unorthodox (gcc/msvc) folks. Just make sure you compile
419 | the LLVM and clang libraries with the same compiler and standard library as you do clang-expand.
420 |
421 | Once you have all that, you can build with:
422 |
423 | ```bash
424 | $ mkdir build && cd build
425 | $ cmake -DLLVM_PATH=/path/to/llvm/ -DFIND_LLVM_VERBOSE_CONFIG=on ..
426 | ```
427 |
428 | ### Docker
429 |
430 | We provide Dockerfiles for Debian, Ubuntu, Fedora and OpenSUSE based images that, once built, have LLVM and clang libraries installed and compiled and contain build scripts to compile the project inside the Docker containers. While this is mainly to make it easier to create reproducible, fast and isolated releases of clang-expand on each of these distributions, these containers may actually be the easiest way for you to compile the project and make changes to it. To build a single container, run something like:
431 |
432 | ```sh
433 | $ docker build --compress --memory 2G --tag clang-expand: --file docker/.Dockerfile
434 | ```
435 |
436 | where `os` is in `{ubuntu, debian, fedora, opensuse}`. You can also pull the image from the [Docker Cloud](http://cloud.docker.com/app/goldsborough/repository/docker/goldsborough/clang-expand/):
437 |
438 | ```sh
439 | $ docker pull goldsborough/clang-expand:-latest
440 | ```
441 |
442 | To then build the project inside the container, you can run:
443 |
444 | ```sh
445 | $ docker run -v build:/home/build -v llvm-build:/llvm/build -v $PWD:/home/project -v $PWD/bin:/home/build/bin clang-expand: ./build.sh
446 | ```
447 |
448 | where `os` is again one of the above. To explain the volumes we are mounting here:
449 |
450 | 1. The named volume `build` is where the project will be built with cmake,
451 | 2. The named volume `llvm-build` is where LLVM and clang will be built with cmake,
452 | 3. `$PWD:/home/clang-expand` mounts your local clang-expand directory under /home,
453 | 4. `$PWD/bin:/home/build/bin` is where all the binaries go. Mount it on the host if you want to keep the binaries.
454 |
455 | You can also just run `docker-compose up` (provided you have `docker-compose` installed) from the project root to build clang-expand on all distributions. Our cmake also has a docker target, so `make docker` does the same as `docker-compose up`.
456 |
457 | ### Windows
458 |
459 | On Windows, you'll want to use cmake-gui and let it generate a solution for Visual Studio 2017 (make sure `llvm-config` is either in the `PATH` or set the variable manually). Depending on how you've built LLVM you could have to add `mincore.lib` as an additional library dependency to the clang-generate project to fix some undefined external symbols.
460 |
461 | ## Documentation
462 |
463 | clang-expand has very extensive in-source documentation which can be generated
464 | with [Doxygen](http://www.doxygen.org). Run `make docs` inside the `build`
465 | folder. You don't need to compile the project for this, just run `cmake ..` and
466 | then `make` the `docs` target.
467 |
468 | ## License
469 |
470 | This project is released under the [MIT
471 | License](http://goldsborough.mit-license.org). For more information, see the
472 | `LICENSE` file.
473 |
474 | ## Authors
475 |
476 | [Peter Goldsborough](http://goldsborough.me) + [cat](https://goo.gl/IpUmJn)
477 | :heart:
478 |
--------------------------------------------------------------------------------
/clang-expand.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | // _ _
3 | // | | | |
4 | // ___| | __ _ _ __ __ _ ______ _____ ___ __ __ _ _ __ __| |
5 | // / __| |/ _` | '_ \ / _` |______/ _ \ \/ / '_ \ / _` | '_ \ / _` |
6 | // | (__| | (_| | | | | (_| | | __/> <| |_) | (_| | | | | (_| |
7 | // \___|_|\__,_|_| |_|\__, | \___/_/\_\ .__/ \__,_|_| |_|\__,_|
8 | // __/ | | |
9 | // |___/ |_|
10 | //
11 | // The MIT License (MIT)
12 | // Copyright (c) 2017 Peter Goldsborough
13 | //
14 | // Permission is hereby granted, free of charge, to any person obtaining a copy
15 | // of this software and associated documentation files (the "Software"), to
16 | // deal in the Software without restriction, including without limitation the
17 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 | // sell copies of the Software, and to permit persons to whom the Software is
19 | // furnished to do so, subject to the following conditions:
20 | //
21 | // The above copyright notice and this permission notice shall be included in
22 | // all copies or substantial portions of the Software.
23 | //
24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30 | // IN THE SOFTWARE.
31 | //===----------------------------------------------------------------------===//
32 |
33 | // Project includes
34 | #include "clang-expand/options.hpp"
35 | #include "clang-expand/result.hpp"
36 | #include "clang-expand/search.hpp"
37 |
38 | // Third-party includes
39 | #include
40 |
41 | // Clang includes
42 | #include
43 | #include
44 |
45 | // LLVM includes
46 | #include
47 | #include
48 | #include
49 |
50 | // Standard includes
51 | #include
52 | #include
53 |
54 | namespace {
55 | llvm::cl::OptionCategory clangExpandCategory("clang-expand options");
56 |
57 | llvm::cl::extrahelp clangExpandCategoryHelp(R"(
58 | Retrieves function, method, operator or macro definitions and optionally
59 | performs automatic parameter replacement. Allows for happy refactoring without
60 | source file gymnastics.
61 | )");
62 |
63 | llvm::cl::opt
64 | fileOption("file",
65 | llvm::cl::desc("The source file of the function to expand"),
66 | llvm::cl::cat(clangExpandCategory));
67 | llvm::cl::alias fileShortOption("f",
68 | llvm::cl::desc("Alias for -file"),
69 | llvm::cl::aliasopt(fileOption));
70 |
71 | llvm::cl::opt
72 | lineOption("line",
73 | llvm::cl::Required,
74 | llvm::cl::desc("The line number of the function to expand"),
75 | llvm::cl::cat(clangExpandCategory));
76 | llvm::cl::alias lineShortOption("l",
77 | llvm::cl::desc("Alias for -line"),
78 | llvm::cl::aliasopt(lineOption));
79 |
80 | llvm::cl::opt
81 | columnOption("column",
82 | llvm::cl::Required,
83 | llvm::cl::desc("The column number of the function to expand"),
84 | llvm::cl::cat(clangExpandCategory));
85 | llvm::cl::alias columnShortOption("c",
86 | llvm::cl::desc("Alias for -column"),
87 | llvm::cl::aliasopt(columnOption));
88 |
89 | llvm::cl::opt
90 | callOption("call",
91 | llvm::cl::init(true),
92 | llvm::cl::desc("Whether to return the source range of the call"),
93 | llvm::cl::cat(clangExpandCategory));
94 |
95 | llvm::cl::opt declarationOption(
96 | "declaration",
97 | llvm::cl::init(true),
98 | llvm::cl::desc("Whether to return the original declaration"),
99 | llvm::cl::cat(clangExpandCategory));
100 |
101 | llvm::cl::opt definitionOption(
102 | "definition",
103 | llvm::cl::init(true),
104 | llvm::cl::desc("Whether to return the original definition"),
105 | llvm::cl::cat(clangExpandCategory));
106 |
107 | llvm::cl::opt rewriteOption(
108 | "rewrite",
109 | llvm::cl::init(true),
110 | llvm::cl::desc("Whether to generate the rewritten (expand) definition"),
111 | llvm::cl::cat(clangExpandCategory));
112 |
113 | llvm::cl::extrahelp
114 | commonHelp(clang::tooling::CommonOptionsParser::HelpMessage);
115 | } // namespace
116 |
117 | auto main(int argc, const char* argv[]) -> int {
118 | using namespace clang::tooling; // NOLINT(build/namespaces)
119 |
120 | CommonOptionsParser options(argc, argv, clangExpandCategory);
121 | const auto& sources = options.getSourcePathList();
122 | auto& db = options.getCompilations();
123 |
124 | if (fileOption.empty()) {
125 | fileOption = sources.front();
126 | }
127 |
128 | // clang-format off
129 | ClangExpand::Search search(fileOption, lineOption, columnOption);
130 | auto result = search.run(db, sources, {
131 | callOption,
132 | declarationOption,
133 | definitionOption,
134 | rewriteOption
135 | });
136 | // clang-format on
137 |
138 | llvm::outs() << result.toJson().dump(2) << '\n';
139 | }
140 |
--------------------------------------------------------------------------------
/cmake/modules/FindLLVM.cmake:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | # Finds LLVM and clang libraries, headers and required flags using llvm-config.
3 | # Sets:
4 | # LLVM_ROOT:
5 | # The root LLVM directory.
6 | # LLVM_BUILD:
7 | # The LLVM build directory.
8 | # LLVM_BIN:
9 | # The LLVM binaries directories.
10 | # LLVM_INCLUDE_DIRS:
11 | # The LLVM includes directories.
12 | # LLVM_LIBRARY_DIRS:
13 | # The LLVM libraries directory.
14 | # LLVM_CXX_FLAGS:
15 | # The compiler flags required to compile LLVM and clang libraries.
16 | # LLVM_LD_FLAGS:
17 | # The linker flags required to compile LLVM and clang libraries.
18 | # LLVM_LD_FLAGS_STRING:
19 | # Like LLVM_LD_FLAGS, but as a string instead of list.
20 | # LLVM_LIBS:
21 | # The list of all LLVM libraries to link.
22 | # LIBCXX_INCLUDE_DIRS:
23 | # The include directory for libc++, if it exists.
24 | ################################################################################
25 |
26 | option(FIND_LLVM_VERBOSE_CONFIG off)
27 |
28 | function(set_llvm_variable variable flags)
29 | execute_process(
30 | COMMAND ${LLVM_CONFIG} ${flags}
31 | RESULT_VARIABLE result_code
32 | OUTPUT_VARIABLE output
33 | OUTPUT_STRIP_TRAILING_WHITESPACE
34 | )
35 | if(result_code)
36 | message(FATAL_ERROR "Failed to execute llvm-config ${flags}, result code: ${result_code}")
37 | else()
38 | string(REPLACE "\n" ";" output ${output})
39 | separate_arguments(output)
40 | if (FIND_LLVM_VERBOSE_CONFIG)
41 | message(STATUS "Found LLVM_${variable}: ${output}")
42 | endif()
43 | set(LLVM_${variable} "${output}" PARENT_SCOPE)
44 | endif()
45 | endfunction()
46 |
47 | message(STATUS "LLVM_PATH is ${LLVM_PATH}")
48 |
49 | find_program(LLVM_CONFIG
50 | NAMES llvm-config
51 | HINTS "${LLVM_PATH}/build/bin" "${LLVM_PATH}"
52 | DOC "Path to llvm-config tool")
53 | if (LLVM_CONFIG)
54 | message(STATUS "Found llvm-config at ${LLVM_CONFIG}")
55 | else()
56 | message(FATAL_ERROR "Could not find llvm-config")
57 | endif()
58 |
59 | set_llvm_variable(ROOT "--src-root")
60 | set_llvm_variable(BUILD "--obj-root")
61 | set_llvm_variable(BIN "--bindir")
62 | set_llvm_variable(INCLUDE_DIRS "--includedir")
63 | set_llvm_variable(LIBRARY_DIRS "--libdir")
64 | set_llvm_variable(CXX_FLAGS "--cxxflags")
65 | set_llvm_variable(LD_FLAGS "--ldflags")
66 | set_llvm_variable(LIBS "--libs;--system-libs")
67 |
68 | set(CLANG_ROOT "${LLVM_ROOT}/tools/clang")
69 | set(CLANG_INCLUDE_DIRS
70 | ${CLANG_ROOT}/include
71 | ${LLVM_BUILD}/tools/clang/include)
72 | set(LLVM_INCLUDE_DIRS
73 | ${LLVM_INCLUDE_DIRS}
74 | ${LLVM_BUILD}/include)
75 |
76 | if (EXISTS "${LLVM_ROOT}/projects/libcxx")
77 | set(LLVM_LIBCXX_INCLUDE_DIRS "${LLVM_ROOT}/projects/libcxx/include")
78 | message(STATUS "Found LLVM_LIBCXX_INCLUDE_DIRS: ${LLVM_LIBCXX_INCLUDE_DIRS}")
79 | endif()
80 |
81 | string(REPLACE ";" " " LLVM_LD_FLAGS_STRING "${LLVM_LD_FLAGS}")
82 |
--------------------------------------------------------------------------------
/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | debian:
4 | build:
5 | context: .
6 | dockerfile: docker/debian.Dockerfile
7 | image: clang-expand:debian
8 | command: ./build.sh debian
9 | volumes:
10 | - build:/home/build
11 | - llvm-build:/llvm/build
12 | - $PWD/../:/home/project
13 | - $PWD/bin:/home/build/bin
14 | fedora:
15 | build:
16 | context: .
17 | dockerfile: docker/fedora.Dockerfile
18 | image: clang-expand:fedora
19 | command: ./build.sh fedora
20 | volumes:
21 | - build:/home/build
22 | - llvm-build:/llvm/build
23 | - $PWD/../:/home/project
24 | - $PWD/bin:/home/build/bin
25 | opensuse:
26 | build:
27 | context: .
28 | dockerfile: docker/opensuse.Dockerfile
29 | image: clang-expand:opensuse
30 | command: ./build.sh opensuse
31 | volumes:
32 | - build:/home/build
33 | - llvm-build:/llvm/build
34 | - $PWD/../:/home/project
35 | - $PWD/bin:/home/build/bin
36 |
37 | volumes:
38 | llvm-build:
39 | build:
40 |
--------------------------------------------------------------------------------
/docker/.dockerignore:
--------------------------------------------------------------------------------
1 | *~
2 |
--------------------------------------------------------------------------------
/docker/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # If the LLVM build folder doesn't exist yet, create it.
4 | if [[ ! -d /llvm/build ]]; then
5 | echo '===---------- Creating /llvm/build folder ----------==='
6 | mkdir /llvm/build
7 | fi
8 |
9 | # Find out what clang is called on here.
10 | which clang++-3.9
11 | if [[ $? -eq 0 ]]; then
12 | export CXX=clang++-3.9
13 | else
14 | export CXX=clang++
15 | fi
16 |
17 | # If the folder is empty, build it.
18 | echo '===---------- Building LLVM and clang ----------==='
19 | cd /llvm/build
20 | cmake -DCMAKE_BUILD_TYPE=Release \
21 | -DLLVM_ENABLE_ASSERTIONS=OFF \
22 | -DCMAKE_C_COMPILER=$C \
23 | -DCMAKE_CXX_COMPILER=$CXX \
24 | ..
25 | make -j4
26 | cd -
27 |
28 | # If the project build folder doesn't exist yet, create it.
29 | if [[ ! -d /home/build ]]; then
30 | echo '===---------- Creating /build folder ----------==='
31 | mkdir /home/build
32 | fi
33 |
34 | # If the folder is empty, build it.
35 | echo "===---------- Building project on $1 ----------==="
36 | cd /home/build
37 | cmake -DLLVM_PATH=/llvm \
38 | -DCMAKE_BUILD_TYPE=Release \
39 | -DCMAKE_C_COMPILER=$C \
40 | -DCMAKE_CXX_COMPILER=$CXX \
41 | -DFIND_LLVM_VERBOSE_CONFIG=on \
42 | -DCLANG_EXPAND_OS_NAME=$1 \
43 | /home/project
44 | make -j4
45 | cd -
46 |
--------------------------------------------------------------------------------
/docker/debian.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM debian:sid
2 | MAINTAINER
3 |
4 | # Install packages.
5 | RUN apt-get update -y \
6 | && apt-get install -y git cmake vim make wget gnupg
7 |
8 | # Get LLVM apt repositories.
9 | RUN wget -O - 'http://apt.llvm.org/llvm-snapshot.gpg.key' | apt-key add - \
10 | && echo 'deb http://apt.llvm.org/unstable/ llvm-toolchain-3.9 main' \
11 | >> /etc/apt/sources.list \
12 | && echo 'deb-src http://apt.llvm.org/unstable/ llvm-toolchain-3.9 main' \
13 | >> /etc/apt/sources.list
14 |
15 | # Install clang-3.9
16 | RUN apt-get update -y && apt-get install -y clang-3.9
17 |
18 | ENV C clang-3.9
19 | ENV CXX clang++-3.9
20 |
21 | # Grab LLVM and clang.
22 | RUN git clone --progress --verbose \
23 | https://github.com/llvm-mirror/llvm.git llvm
24 | RUN git clone --progress --verbose \
25 | https://github.com/llvm-mirror/clang.git llvm/tools/clang
26 |
27 | # These volumes should be mounted as named volumes.
28 | VOLUME /llvm/build /home/build
29 |
30 | # These volumes should be mounted on the host.
31 | VOLUME /home/project /home/build/bin
32 |
33 | WORKDIR /home
34 | COPY build.sh .
35 | CMD ["./build.sh", "debian"]
36 |
--------------------------------------------------------------------------------
/docker/fedora.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM fedora
2 | MAINTAINER
3 |
4 | # Install packages.
5 | RUN dnf update -y \
6 | && dnf install -y git cmake vim make clang python ncurses-devel
7 |
8 | ENV C clang
9 | ENV CXX clang++
10 |
11 | # Grab LLVM and clang.
12 | RUN git clone --progress --verbose \
13 | https://github.com/llvm-mirror/llvm.git llvm
14 | RUN git clone --progress --verbose \
15 | https://github.com/llvm-mirror/clang.git llvm/tools/clang
16 |
17 | # These volumes should be mounted as named volumes.
18 | VOLUME /llvm/build /home/build
19 |
20 | # These volumes should be mounted on the host.
21 | VOLUME /home/project /home/build/bin
22 |
23 | WORKDIR /home
24 | COPY build.sh .
25 | CMD ["./build.sh", "fedora"]
26 |
--------------------------------------------------------------------------------
/docker/opensuse.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM opensuse
2 | MAINTAINER
3 |
4 | # Install packages.
5 | RUN zypper --non-interactive refresh \
6 | && zypper --non-interactive install \
7 | git cmake vim make llvm-clang gcc5 gcc5-c++ libstdc++6-devel-gcc5
8 |
9 | ENV C clang-3.8
10 | ENV CXX clang++-3.8
11 |
12 | # Grab LLVM and clang.
13 | RUN git clone --progress --verbose \
14 | https://github.com/llvm-mirror/llvm.git llvm
15 | RUN git clone --progress --verbose \
16 | https://github.com/llvm-mirror/clang.git llvm/tools/clang
17 |
18 | # These volumes should be mounted as named volumes.
19 | VOLUME /llvm/build /home/build
20 |
21 | # These volumes should be mounted on the host.
22 | VOLUME /home/project /home/build/bin
23 |
24 | WORKDIR /home
25 | COPY build.sh .
26 | CMD ["./build.sh", "opensuse"]
27 |
--------------------------------------------------------------------------------
/docker/ubuntu.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu
2 | MAINTAINER
3 |
4 | # Install packages.
5 | RUN apt-get update -y \
6 | && apt-get install -y git cmake vim make wget gnupg
7 |
8 | # Get LLVM apt repositories.
9 | RUN wget -O - 'http://apt.llvm.org/llvm-snapshot.gpg.key' | apt-key add - \
10 | && echo 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.9 main' \
11 | >> /etc/apt/sources.list \
12 | && echo 'deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.9 main' \
13 | >> /etc/apt/sources.list
14 |
15 | # Install clang-3.9
16 | RUN apt-get update -y && apt-get install -y clang-3.9
17 |
18 | ENV C clang-3.9
19 | ENV CXX clang++-3.9
20 |
21 | # Grab LLVM and clang.
22 | RUN git clone --progress --verbose \
23 | https://github.com/llvm-mirror/llvm.git llvm
24 | RUN git clone --progress --verbose \
25 | https://github.com/llvm-mirror/clang.git llvm/tools/clang
26 |
27 | # These volumes should be mounted as named volumes.
28 | VOLUME /llvm/build /home/build
29 |
30 | # These volumes should be mounted on the host.
31 | VOLUME /home/project /home/build/bin
32 |
33 | WORKDIR /home
34 | COPY build.sh .
35 | CMD ["./build.sh", "ubuntu"]
36 |
--------------------------------------------------------------------------------
/extra/clang-expand.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/goldsborough/clang-expand/e1e8dd1fdbe59b9f708f0cf9f9787c03cdfec0bf/extra/clang-expand.gif
--------------------------------------------------------------------------------
/include/clang-expand/common/assignee-data.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_COMMON_ASSIGNEE_DATA_HPP
26 | #define CLANG_EXPAND_COMMON_ASSIGNEE_DATA_HPP
27 |
28 | // LLVM includes
29 | #include
30 | #include
31 | #include
32 |
33 | // Standard includes
34 | #include
35 |
36 | namespace ClangExpand {
37 | /// Stores information about the assignee of a call expression.
38 | ///
39 | /// In `int x = f(5);`, the variable `x` is the *assignee*.
40 | class AssigneeData {
41 | public:
42 | // <<=/>>= should be the longest compound assignment.
43 | using OperatorString = llvm::SmallString<3>;
44 |
45 | class Builder;
46 |
47 | /// Stores information about the type of the assignee.
48 | struct Type {
49 | /// Constructor.
50 | explicit Type(std::string name_ = std::string(),
51 | bool isDefaultConstructible_ = true) noexcept;
52 |
53 | /// A string representation of the type.
54 | std::string name;
55 |
56 | /// Whether the type is default constructible or not.
57 | bool isDefaultConstructible;
58 | };
59 |
60 | /// Returns true if the assignee's type is default-constructible or if there
61 | /// is no type
62 | /// information at all. There is no type information if the call is as
63 | /// assignment rather than a
64 | /// construction. If this function returns false, it is not safe to expand a
65 | /// function with at
66 | /// least one return statement that is not the last statement of the function.
67 | /// For example, in:
68 | ///
69 | /// ```.cpp
70 | /// int& f(int& x) {
71 | /// if (x > 10) {
72 | /// x += 1;
73 | /// return x;
74 | /// }
75 | /// return x;
76 | /// }
77 | /// ```
78 | ///
79 | /// It would not be safe to expand a call expression like this:
80 | ///
81 | /// ```.cpp
82 | /// int x = 12;
83 | /// int& y = f(x);
84 | /// ```
85 | ///
86 | /// As this would translate to an expansion where the reference can not be
87 | /// bound immediately (or
88 | /// the type default-constructed):
89 | ///
90 | /// ```.cpp
91 | /// int& y; // invalid
92 | /// if (x > 10) {
93 | /// x += 1;
94 | /// y = x;
95 | /// }
96 | /// y = x;
97 | /// ```
98 | ///
99 | /// If only the last return statement is given, this expression is valid,
100 | /// however.
101 | bool isDefaultConstructible() const noexcept;
102 |
103 | /// Converts the `AssigneeData` to a string like `"int x ="`. If `withType` is
104 | /// true, the type (like `int` in the example) will be included (this if for
105 | /// *declarations*). Else, the type is omitted (for *assignments*). Note that
106 | /// the assignee is not always assigned with `=`, but sometimes also any other
107 | /// operator like `+=` or `<<=` (compound operators).
108 | std::string toAssignment(bool withType = true) const;
109 |
110 | /// Converts the `AssigneeData` to a string like `int x;` that would declare
111 | /// the assignee (i.e. the type and name, followed by a semicolon).
112 | std::string toDeclaration() const;
113 |
114 | /// The operator used in the assignment (`=`, `+=`, `<<=` etc.).
115 | OperatorString op;
116 |
117 | /// The name of the variable being assigned to.
118 | std::string name;
119 |
120 | /// If the assignment is a variable declaration and not just an assignment,
121 | /// the type of the variable being declared. The type is further split into
122 | /// the name (string representation) of the type and a boolean flag indicating
123 | /// whethert the type is default constructible.
124 | llvm::Optional type;
125 | };
126 |
127 | /// Helper class to build an `AssigneeData` structure.
128 | class AssigneeData::Builder {
129 | public:
130 | /// Constructs a new builder with a temporary `AssigneeData` instance.
131 | explicit Builder(AssigneeData&& assignee = AssigneeData());
132 | Builder(const Builder&) = delete;
133 | Builder& operator=(const Builder&) = delete;
134 |
135 | /// Sets the name of the assignee.
136 | Builder& name(const llvm::StringRef& name);
137 |
138 | /// Sets the type information of the assignee.
139 | Builder& type(const llvm::StringRef& name,
140 | bool isDefaultConstructible = true);
141 |
142 | /// Sets the operator information of the assignee.
143 | Builder& op(const llvm::StringRef& op);
144 |
145 | /// Finishes building the `AssigneeData` and returns it.
146 | AssigneeData build();
147 |
148 | private:
149 | /// The `AssigneeData` being built.
150 | AssigneeData _assignee;
151 | };
152 |
153 | } // namespace ClangExpand
154 |
155 | #endif // CLANG_EXPAND_COMMON_ASSIGNEE_DATA_HPP
156 |
--------------------------------------------------------------------------------
/include/clang-expand/common/call-data.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_COMMON_CALL_DATA_HPP
26 | #define CLANG_EXPAND_COMMON_CALL_DATA_HPP
27 |
28 | // Project includes
29 | #include "clang-expand/common/assignee-data.hpp"
30 | #include "clang-expand/common/range.hpp"
31 |
32 | // LLVM includes
33 | #include
34 |
35 | // Standard includes
36 | #include
37 |
38 | namespace ClangExpand {
39 |
40 | /// Stores information about a function call.
41 | struct CallData {
42 | /// Constructs the `CallData` with the extent of the call, leaving the `base`
43 | /// string empty and the `assignee` data null.
44 | explicit CallData(Range&& extent_);
45 |
46 | /// Constructs the `CallData` with an `assignee` and the extent of the call.
47 | CallData(AssigneeData&& assignee, Range&& extent_);
48 |
49 | /// Utility function to check if declaring the type of the assignee of the
50 | /// function return value is required. This is the case if there is an
51 | /// assignee at all and we picked up the type of the assignee (which would not
52 | /// be the case for *assignments* as opposed to constructions).
53 | bool requiresDeclaration() const noexcept;
54 |
55 | /// Any base expression to the function call, e.g. the `object` in
56 | /// `object.method()`.
57 | std::string base;
58 |
59 | /// Information about the assignee of the call expression, including things
60 | /// like the type and name of the variable as well as the assignment operator
61 | /// (we also refer to compound operators like `+=` to assignments in this
62 | /// case).
63 | llvm::Optional assignee;
64 |
65 | /// The source range of the entire call expression, from the first character
66 | /// of any variable declaration to the final semicolon. The semicolon is
67 | /// included in the range.
68 | Range extent;
69 | };
70 | } // namespace ClangExpand
71 |
72 | #endif // CLANG_EXPAND_COMMON_CALL_DATA_HPP
73 |
--------------------------------------------------------------------------------
/include/clang-expand/common/canonical-location.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_COMMON_CANONICAL_LOCATION_HPP
26 | #define CLANG_EXPAND_COMMON_CANONICAL_LOCATION_HPP
27 |
28 | namespace clang {
29 | class FileEntry;
30 | class SourceLocation;
31 | class SourceManager;
32 | }
33 |
34 | namespace ClangExpand {
35 |
36 | /// A location structure that always compares equal for identical offset.
37 | ///
38 | /// `clang::SourceLocation`s don't always compare equal, even if they point at
39 | /// the exact same location. What does always, work, however, is checking that
40 | /// the files of the two `clang::SourceLocation`s and the offsets into those
41 | /// files are the same
42 | struct CanonicalLocation {
43 | /// Converts a `clang::SourceLocation` into a `CanonicalLocation`.
44 | CanonicalLocation(const clang::SourceLocation& location,
45 | const clang::SourceManager& sourceManager);
46 |
47 | /// Tests two `CanonicalLocation`s for equality.
48 | bool operator==(const CanonicalLocation& other) const noexcept;
49 |
50 | /// Tests two `CanonicalLocation`s for inequality.
51 | bool operator!=(const CanonicalLocation& other) const noexcept;
52 |
53 | /// The file entry of the location.
54 | const clang::FileEntry* file;
55 |
56 | /// The offset (index) into the file.
57 | unsigned offset;
58 | };
59 | } // namespace ClangExpand
60 |
61 |
62 | #endif // CLANG_EXPAND_COMMON_CANONICAL_LOCATION_HPP
63 |
--------------------------------------------------------------------------------
/include/clang-expand/common/context-data.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_COMMON_CONTEXT_DATA_HPP
26 | #define CLANG_EXPAND_COMMON_CONTEXT_DATA_HPP
27 |
28 | // Clang includes
29 | #include
30 |
31 | // LLVM includes
32 | #include
33 |
34 | // Standard includes
35 | #include
36 |
37 | namespace ClangExpand {
38 |
39 | /// Stores information about a context (namespace, class name etc.).
40 | ///
41 | /// C++ allows classes inside namespaces to have the same name as the namespace
42 | /// (`namespace X { struct X {}; }`), so we can't just store the name, we also
43 | /// need the `Decl::Kind`.
44 | struct ContextData {
45 | /// Constructor.
46 | ContextData(clang::Decl::Kind kind_, const llvm::StringRef& name_)
47 | : kind(kind_), name(name_.str()) {
48 | }
49 |
50 | /// The `clang::Decl::Kind` of the context (usually CXXRecord or Namespace).
51 | clang::Decl::Kind kind;
52 |
53 | /// The name of the context (class, namespace etc.).
54 | std::string name;
55 | };
56 | } // namespace ClangExpand
57 |
58 | #endif // CLANG_EXPAND_COMMON_CONTEXT_DATA_HPP
59 |
--------------------------------------------------------------------------------
/include/clang-expand/common/declaration-data.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_COMMON_DECLARATION_DATA_HPP
26 | #define CLANG_EXPAND_COMMON_DECLARATION_DATA_HPP
27 |
28 | // Project includes
29 | #include "clang-expand/common/context-data.hpp"
30 | #include "clang-expand/common/location.hpp"
31 |
32 | // Third party includes
33 | #include
34 |
35 | // LLVM includes
36 | #include
37 | #include
38 |
39 | // Standard includes
40 | #include
41 |
42 | namespace ClangExpand {
43 | /// Stores information about a function declaration.
44 | ///
45 | /// This information is used to uniquely identify any function that we might
46 | /// look for. Note that the function could actually be a constructor or operator
47 | /// overload.
48 | struct DeclarationData {
49 | using ParameterMap = llvm::StringMap;
50 |
51 | /// Constructor.
52 | explicit DeclarationData(std::string name_, Location location_);
53 |
54 | /// Converts the `DeclarationData` to JSON.
55 | nlohmann::json toJson() const;
56 |
57 | /// The name of the function (or operator).
58 | std::string name;
59 |
60 | /// The raw source text of the entire function declaration.
61 | ///
62 | /// If the declaration is also a definition, this will include the definition.
63 | std::string text;
64 |
65 | /// The contexts of the function (namespaces, class names etc.).
66 | ///
67 | /// The order of these contexts is from most nested to least nested, i.e.
68 | /// given a function, its contexts can be compared from "the inside out". For
69 | /// example, given this function definition:
70 | ///
71 | /// ```.cpp
72 | /// namesapce A {
73 | /// namespace B {
74 | /// class C {
75 | /// void f();
76 | /// };
77 | /// }
78 | /// }
79 | /// ```
80 | ///
81 | /// The contexts will be 'C', 'B', 'A' (in this order!).
82 | llvm::SmallVector contexts;
83 |
84 | /// The types of the parameters as they appear in the function definition.
85 | ///
86 | /// The type strings stored are fully qualified to retain as much information
87 | /// as possible across for serialization between symbol and definition search.
88 | /// More precisely, the type information is retrieved through:
89 | /// `parameter->getOriginalType().getCanonicalType().getAsString(policy)`,
90 | /// where `parameter` is a `ParmVarDecl` and `policy` is an appropriate
91 | /// `PrintingPolicy` retrieved from the `ASTContext` that stores the full
92 | /// qualification of the name.
93 | llvm::SmallVector parameterTypes;
94 |
95 | /// The mapping from parameter names to respective argument expressions.
96 | ///
97 | /// For example, given this function and call:
98 | /// ```.cpp
99 | /// void f(int x, double y);
100 | /// f(1, g(2));
101 | /// ```
102 | ///
103 | /// where `g` is some double-valued function, the mapping will be:
104 | /// - x -> 1
105 | /// - y -> g(2)
106 | /// such that during rewriting, every ocurrence of `x` and `y` inside the
107 | /// function can be replaced with `1` and `g(2)`, respectively.
108 | ParameterMap parameterMap;
109 |
110 | /// The location of the function declaration (right at the name of the
111 | /// function).
112 | Location location;
113 | };
114 | } // namespace ClangExpand
115 |
116 | #endif // CLANG_EXPAND_COMMON_DECLARATION_DATA_HPP
117 |
--------------------------------------------------------------------------------
/include/clang-expand/common/definition-data.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_COMMON_DEFINITION_DATA_HPP
26 | #define CLANG_EXPAND_COMMON_DEFINITION_DATA_HPP
27 |
28 | // Project includes
29 | #include "clang-expand/common/location.hpp"
30 |
31 | // Third party includes
32 | #include
33 |
34 | // Standard includes
35 | #include
36 |
37 | namespace clang {
38 | class FunctionDecl;
39 | class ASTContext;
40 | }
41 |
42 | namespace ClangExpand {
43 | struct Query;
44 |
45 | /// Stores data about the definition of a function.
46 | struct DefinitionData {
47 | /// Collects the entire `DefinitionData` for the function. The `query` passed
48 | /// should already have been through symbol search and must store `CallData`
49 | /// and `DeclarationData`.
50 | static DefinitionData Collect(const clang::FunctionDecl& function,
51 | clang::ASTContext& context,
52 | const Query& query);
53 |
54 | /// Converts the `DefinitionData` to JSON.
55 | nlohmann::json toJson() const;
56 |
57 | /// The `Location` of the definition in the source.
58 | Location location;
59 |
60 | /// The original, untouched source text of the definition.
61 | std::string original;
62 |
63 | /// The rewritten (expanded) source text of the definition.
64 | std::string rewritten;
65 |
66 | /// Whether this definition is from a macro or a real function.
67 | bool isMacro{false};
68 | };
69 | } // namespace ClangExpand
70 |
71 | #endif // CLANG_EXPAND_COMMON_DEFINITION_DATA_HPP
72 |
--------------------------------------------------------------------------------
/include/clang-expand/common/definition-rewriter.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_COMMON_DEFINITION_REWRITER_HPP
26 | #define CLANG_EXPAND_COMMON_DEFINITION_REWRITER_HPP
27 |
28 | // Clang includes
29 | #include
30 |
31 | // LLVM includes
32 | #include
33 | #include
34 | #include
35 |
36 | // Standard includes
37 | #include
38 |
39 | namespace clang {
40 | class ASTContext;
41 | class Rewriter;
42 | class Stmt;
43 | class SourceLocation;
44 | class MemberExpr;
45 | class ReturnStmt;
46 | }
47 |
48 | namespace ClangExpand {
49 | struct CallData;
50 |
51 | /// Class to rewrite a function body for expansion purposes.
52 | ///
53 | /// This class performs the heavy lifting in terms of rewriting a function body.
54 | /// It rewrites `return` statements to assignments (under certain
55 | /// circumstances), prefixes member expressions with their base objects and most
56 | /// importantly replaces parameter references with the passed argument
57 | /// expressions.
58 | ///
59 | /// This class only stores references to the objects it is constructed with. It
60 | /// should therefore not be stored, but used just like a function call with all
61 | /// arguments stored on the stack.
62 | class DefinitionRewriter
63 | : public clang::RecursiveASTVisitor {
64 | public:
65 | using super = clang::RecursiveASTVisitor;
66 | using ParameterMap = llvm::StringMap;
67 |
68 | /// Constructor.
69 | explicit DefinitionRewriter(clang::Rewriter& rewriter,
70 | const ParameterMap& parameterMap,
71 | const CallData& call,
72 | clang::ASTContext& context);
73 |
74 | /// Traverses the body of a function to rewrite.
75 | bool VisitStmt(clang::Stmt* body);
76 |
77 | /// Traversed `clang::TypeLoc`, which we use to replace type template
78 | /// parameters.
79 | bool VisitTypeLoc(clang::TypeLoc typeLocation);
80 |
81 | /// Rewrites all `return` statements to assignments, according to the stored
82 | /// `CallData`. `return` statement locations are stored during the traversal
83 | /// in `VisitStmt`. After this is done, this method can be called to actually
84 | /// replace each `return ` statement to ` = `.
85 | ///
86 | /// There are two required preconditions to calling this method:
87 | ///
88 | /// 1. The `assignee` member of the `CallData` must not be nullopt`.
89 | /// 2. There must be at least one return statement in the body of
90 | /// the function. This invariant *should* follow from (1), since there
91 | /// *should* be no assignee if there is no return statement.
92 | ///
93 | /// \returns True if it is necessary to prepend a declaration of the assignee
94 | /// to the function body (depending on the number of return statements), else
95 | /// false.
96 | bool rewriteReturnsToAssignments(const clang::Stmt& body);
97 |
98 | private:
99 | /// Stores the location of a return statement for later use. Once all return
100 | /// locations have been collected like this, `rewriteReturnsToAssignments` can
101 | /// later be called to perform the actual replacements.
102 | void _recordReturn(const clang::ReturnStmt& returnStatement,
103 | const CallData& call);
104 |
105 | /// Replaces a single return location with the given text. The location should
106 | /// probably come out of `_returnLocations`.
107 | void _rewriteReturn(const clang::SourceLocation& begin,
108 | const std::string& replacement);
109 |
110 | /// Handles rewriting a member expression. This is needed when the function
111 | /// being rewritten is a method. In that case we need to prefix every
112 | /// reference to a field or method with the base of the function (e.g. the 'x'
113 | /// in `x.foo()`).
114 | void _rewriteMemberExpression(const clang::MemberExpr& member);
115 |
116 | void _rewriteNonTypeTemplateParameterExpression(
117 | const clang::SubstNonTypeTemplateParmExpr& nonType);
118 |
119 | /// A rewriter to mess with the source text.
120 | clang::Rewriter& _rewriter;
121 |
122 | /// A reference to a parameter map, for replacing parameter uses with argument
123 | /// expressions.
124 | const ParameterMap& _parameterMap;
125 |
126 | /// A reference to a `CallData` structure.
127 | const CallData& _call;
128 |
129 | /// The current `clang::ASTContext`.
130 | clang::ASTContext& _context;
131 |
132 | /// Stores members we have rewritten, because sometimes they are encountered
133 | /// twice inside `VisitStmt` (dunno why).
134 | llvm::SmallPtrSet _rewrittenMembers;
135 |
136 | /// Stores the locations of return statements (at the 'r') so we can later
137 | /// rewrite them.
138 | llvm::SmallVector _returnLocations;
139 | };
140 | } // namespace ClangExpand
141 |
142 | #endif // CLANG_EXPAND_COMMON_DEFINITION_REWRITER_HPP
143 |
--------------------------------------------------------------------------------
/include/clang-expand/common/location.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_COMMON_LOCATION_HPP
26 | #define CLANG_EXPAND_COMMON_LOCATION_HPP
27 |
28 | // Project includes
29 | #include "clang-expand/common/offset.hpp"
30 |
31 | // Third party includes
32 | #include
33 |
34 | // LLVM includes
35 | #include
36 |
37 | // Standard includes
38 | #include
39 |
40 | namespace clang {
41 | class SourceLocation;
42 | class SourceManager;
43 | }
44 |
45 | namespace ClangExpand {
46 |
47 | /// An easier-to-use representaiton of a source location.
48 | ///
49 | /// `clang::SourceLocation`s are meant to be stored as efficiently as possible
50 | /// in the AST to keep it small. `SourceLocation` are really just IDs or indices
51 | /// into a "location-table", so this table must be consulted through the source
52 | /// manager to go from a `SourceLocation` to the filename, line and/or column
53 | /// that the `SourceLocation` represents. Meanwhile, this `Location` class is
54 | /// much less space efficient but stores all important information inside (like
55 | /// a "fat" `SourceLocation`). This is useful since we need such `Locations` a
56 | /// lot when doing our processing as well as for final output to stdout.
57 | struct Location {
58 | /// Constructs a `Location` from a `clang::SourceLocation` using the source
59 | /// manager.
60 | Location(const clang::SourceLocation& location,
61 | const clang::SourceManager& sourceManager);
62 |
63 | /// Constructs a `Location` from a filename and `(line, column)` pair.
64 | Location(const llvm::StringRef& filename_, unsigned line, unsigned column);
65 |
66 | /// Converts the `Location` to JSON.
67 | nlohmann::json toJson() const;
68 |
69 | /// The name of the file this location is from.
70 | std::string filename;
71 |
72 | /// The offset into the file (a `(line, column)` pair).
73 | Offset offset;
74 | };
75 | } // namespace ClangExpand
76 |
77 | #endif // CLANG_EXPAND_COMMON_LOCATION_HPP
78 |
--------------------------------------------------------------------------------
/include/clang-expand/common/offset.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_COMMON_OFFSET_HPP
26 | #define CLANG_EXPAND_COMMON_OFFSET_HPP
27 |
28 | // Third party includes
29 | #include
30 |
31 | namespace clang {
32 | class SourceLocation;
33 | class SourceManager;
34 | }
35 |
36 | namespace ClangExpand {
37 | /// An offset into a file, represented by a `(line, column)` pair. Both the line
38 | /// and the column start are 1-indexed, as they are in clang.
39 | struct Offset {
40 | /// Constructs an `Offset` by converting a `clang::SourceLocation`.
41 | Offset(const clang::SourceLocation& location,
42 | const clang::SourceManager& sourceManager);
43 |
44 | /// Constructor.
45 | Offset(unsigned line_, unsigned column_);
46 |
47 | /// Converts the `Offset` to JSON.
48 | nlohmann::json toJson() const;
49 |
50 | /// The 1-indexed line (row) of the location.
51 | unsigned line;
52 |
53 | /// The 1-indexed column (offset into the line) of the loction.
54 | unsigned column;
55 | };
56 | } // namespace ClangExpand
57 |
58 | #endif // CLANG_EXPAND_COMMON_OFFSET_HPP
59 |
--------------------------------------------------------------------------------
/include/clang-expand/common/query.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_COMMON_QUERY_HPP
26 | #define CLANG_EXPAND_COMMON_QUERY_HPP
27 |
28 | // Project includes
29 | #include "clang-expand/common/call-data.hpp"
30 | #include "clang-expand/common/declaration-data.hpp"
31 | #include "clang-expand/common/definition-data.hpp"
32 | #include "clang-expand/options.hpp"
33 |
34 | // LLVM includes
35 | #include
36 |
37 | namespace ClangExpand {
38 |
39 | /// Stores the options and state of an ongoing query.
40 | ///
41 | /// A `Query` object is created inside `run()` and passed through all stages of
42 | /// the tool to collect and store data. After the search has finished, the
43 | /// `Query` can be converted to a `Result` and finally printed to the console.
44 | struct Query {
45 | /// Constructs a fresh `Query` with the given `Options`.
46 | explicit Query(Options options_) : options(options_) {
47 | }
48 |
49 | /// Utility method to test if it is necessary to collect `DeclarationData`.
50 | /// This will only be the case if the user requested `DeclarationData`, or if
51 | /// the user requested information about the definition of the function.
52 | bool requiresDeclaration() const noexcept {
53 | return options.wantsDeclaration || requiresDefinition();
54 | }
55 |
56 | /// Utility method to test if it is necessary to collect `DefinitionData`.
57 | /// This is the case if the user wants the original or rewritten definition,
58 | /// or both.
59 | bool requiresDefinition() const noexcept {
60 | return options.wantsDefinition || options.wantsRewritten;
61 | }
62 |
63 | /// Utility method to check, after symbol search, whether the search was not
64 | /// successful. This function respects command line options, i.e. if the query
65 | /// has no `DeclarationData` and the user did not request such data,
66 | /// `foundNothing` will not return true (report a failure).
67 | bool foundNothing() const noexcept {
68 | return requiresDeclaration() && (!declaration && !definition);
69 | }
70 |
71 | /// Possibly collected `CallData`.
72 | llvm::Optional call;
73 |
74 | /// Possibly collected `DeclarationData`.
75 | llvm::Optional declaration;
76 |
77 | /// Possibly collected `DefinitionData`.
78 | llvm::Optional definition;
79 |
80 | /// The `Options` of the query (i.e. what information the user wants).
81 | const Options options;
82 | };
83 |
84 | } // namespace ClangExpand
85 |
86 | #endif // CLANG_EXPAND_COMMON_QUERY_HPP
87 |
--------------------------------------------------------------------------------
/include/clang-expand/common/range.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_COMMON_RANGE_HPP
26 | #define CLANG_EXPAND_COMMON_RANGE_HPP
27 |
28 | // Project includes
29 | #include "clang-expand/common/offset.hpp"
30 |
31 | // Third party includes
32 | #include
33 |
34 | namespace clang {
35 | class SourceManager;
36 | class SourceRange;
37 | }
38 |
39 | namespace ClangExpand {
40 | /// A range of source code, represented by a start and end offset.
41 | struct Range {
42 | /// Constructs a range from a `clang::SourceRange` and `clang::SourceManager`,
43 | /// used to obtain the
44 | /// strat and end `Offset`s.
45 | Range(const clang::SourceRange& range,
46 | const clang::SourceManager& sourceManager);
47 |
48 | /// Constructor.
49 | Range(Offset begin_, Offset end_);
50 |
51 | /// Converts the `Range` to JSON.
52 | nlohmann::json toJson() const;
53 |
54 | /// The starting offset.
55 | Offset begin;
56 |
57 | /// The ending offset. May be inclusive or exclusive depending on the context.
58 | Offset end;
59 | };
60 | } // namespace ClangExpand
61 |
62 | #endif // CLANG_EXPAND_COMMON_RANGE_HPP
63 |
--------------------------------------------------------------------------------
/include/clang-expand/common/routines.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_COMMON_ROUTINES_HPP
26 | #define CLANG_EXPAND_COMMON_ROUTINES_HPP
27 |
28 | // Standard includes
29 | #include
30 |
31 | namespace clang {
32 | class SourceLocation;
33 | class SourceManager;
34 | class LangOptions;
35 | class SourceRange;
36 | class ASTContext;
37 | }
38 |
39 | namespace llvm {
40 | class Twine;
41 | }
42 |
43 | namespace ClangExpand {
44 | namespace Routines {
45 |
46 | /// Compares two source locations for equality in a way that actually works.
47 | ///
48 | /// \see CanonicalLocation
49 | bool locationsAreEqual(const clang::SourceLocation& first,
50 | const clang::SourceLocation& second,
51 | const clang::SourceManager& sourceManager);
52 |
53 | /// Retrieves the raw source text within a range, as a string.
54 | std::string getSourceText(const clang::SourceRange& range,
55 | clang::SourceManager& sourceManager,
56 | const clang::LangOptions& languageOptions);
57 |
58 | /// Retrieves the raw source text within a range, as a string. Passes the source
59 | /// manager and language options from the `ASTContext` to the other overload.
60 | std::string getSourceText(const clang::SourceRange& range,
61 | clang::ASTContext& context);
62 |
63 | /// Turns a file path into an absolute file path.
64 | std::string makeAbsolute(const std::string& filename);
65 |
66 | /// Prints an error message to stderr and exits. the program.
67 | [[noreturn]] void error(const char* message);
68 |
69 | /// Prints an error message to stderr and exits. the program. The message is
70 | /// taken as the result of calling `twine.str()`.
71 | [[noreturn]] void error(llvm::Twine&& twine);
72 |
73 | } // namespace Routines
74 | } // namespace ClangExpand
75 |
76 |
77 | #endif // CLANG_EXPAND_COMMON_ROUTINES_HPP
78 |
--------------------------------------------------------------------------------
/include/clang-expand/definition-search/action.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_DEFINITION_SEARCH_ACTION_HPP
26 | #define CLANG_EXPAND_DEFINITION_SEARCH_ACTION_HPP
27 |
28 | // Clang includes
29 | #include
30 |
31 | // Standard includes
32 | #include
33 | #include
34 | #include
35 |
36 | namespace clang {
37 | class CompilerInstance;
38 | class ASTConsumer;
39 | }
40 |
41 | namespace llvm {
42 | class StringRef;
43 | }
44 |
45 | namespace ClangExpand {
46 | struct Query;
47 | }
48 |
49 | namespace ClangExpand {
50 | namespace DefinitionSearch {
51 |
52 | /// \ingroup DefinitionSearch
53 | ///
54 | /// The first entry point into the definition search phase.
55 | ///
56 | /// The only real responsibility of this class is to return a `nullptr` when
57 | /// invoked on the declaration file and otherwise the
58 | /// `DefinitionSearch::Consumer` (a `clang::ASTConsumer`).
59 | class Action : public clang::ASTFrontendAction {
60 | public:
61 | using super = clang::ASTFrontendAction;
62 | using ASTConsumerPointer = std::unique_ptr;
63 |
64 | /// Constructor, taking the file in which the found function was declared and
65 | /// the ongoing `Query` object. The `declarationFile` is needed because the
66 | /// `Action` will skip this file, since we already would have found its
67 | /// definition during symbol search, if it had one.
68 | Action(const std::string& declarationFile, Query& query);
69 |
70 | /// If the `Action` is invoked on the `declarationFile` argument to the
71 | /// constructor, returns a `nullptr`. Else returns a
72 | /// `DefinitionSearch::Consumer` to continue the pipeline.
73 | ASTConsumerPointer CreateASTConsumer(clang::CompilerInstance& compiler,
74 | llvm::StringRef filename) override;
75 |
76 | private:
77 | /// The file in which the declaration was found. While a `std::string&` would
78 | /// work, we actually translate the `declarationFile` to an absolute path, so
79 | /// storing a `std::string` value.
80 | std::string _declarationFile;
81 |
82 | /// The ongoing `Query` object.
83 | Query& _query;
84 | };
85 |
86 | } // namespace DefinitionSearch
87 | } // namespace ClangExpand
88 |
89 | #endif // CLANG_EXPAND_DEFINITION_SEARCH_ACTION_HPP
90 |
--------------------------------------------------------------------------------
/include/clang-expand/definition-search/consumer.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_DEFINITION_SEARCH_CONSUMER_HPP
26 | #define CLANG_EXPAND_DEFINITION_SEARCH_CONSUMER_HPP
27 |
28 | // Project includes
29 | #include "clang-expand/definition-search/match-handler.hpp"
30 |
31 | // Clang includes
32 | #include
33 |
34 | namespace clang {
35 | class ASTContext;
36 | }
37 |
38 | namespace ClangExpand {
39 | struct Query;
40 | }
41 |
42 | namespace ClangExpand {
43 | namespace DefinitionSearch {
44 |
45 | /// \ingroup DefinitionSearch
46 | ///
47 | /// This `clang::ASTConsumer` is a very simple class that receives the ongoing
48 | /// `Query` instance with information collected during symbol search and matches
49 | /// on all functions with the same *name* (only) as the one whose declaration we
50 | /// found. The only other thing we can match for is that the function have a
51 | /// definiton, since that is what we are interested in in this phase.
52 | class Consumer : public clang::ASTConsumer {
53 | public:
54 | /// Constructor, taking the ongoing `Query` object.
55 | explicit Consumer(Query& query);
56 |
57 | /// Creates an ASTMatcher expression and dispatches it on the translation
58 | /// unit. The goal is to find functions with the same names as the function
59 | /// found in the `DeclarationData`.
60 | void HandleTranslationUnit(clang::ASTContext& context) override;
61 |
62 | private:
63 | /// The ongoing `Query` object.
64 | Query& _query;
65 |
66 | /// The match handler the consumer will dispatch.
67 | MatchHandler _matchHandler;
68 | };
69 |
70 | } // namespace DefinitionSearch
71 | } // namespace ClangExpand
72 |
73 | #endif // CLANG_EXPAND_DEFINITION_SEARCH_CONSUMER_HPP
74 |
--------------------------------------------------------------------------------
/include/clang-expand/definition-search/match-handler.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_DEFINITION_SEARCH_MATCH_HANDLER_HPP
26 | #define CLANG_EXPAND_DEFINITION_SEARCH_MATCH_HANDLER_HPP
27 |
28 | // Clang includes
29 | #include
30 |
31 | namespace clang {
32 | class ASTContext;
33 | class FunctionDecl;
34 | }
35 |
36 | namespace ClangExpand {
37 | struct Query;
38 | }
39 |
40 | namespace ClangExpand {
41 | namespace DefinitionSearch {
42 |
43 | /// \ingroup DefinitionSearch
44 | ///
45 | /// The match handler of the definition search phase.
46 | ///
47 | /// This class is used to match on functions, check that they are the kind we
48 | /// expect from the `DeclarationData` we collected and finally collect
49 | /// `DefinitionData` which contains the definition text of the function we are
50 | /// matching, as well as possibly rewritten (expanded) source text.
51 | class MatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback {
52 | public:
53 | using MatchResult = clang::ast_matchers::MatchFinder::MatchResult;
54 |
55 | /// Constructs the `MatchHandler` with the ongoing `Query` object.
56 | explicit MatchHandler(Query& query);
57 |
58 | /// Runs the `MatchHandler` for a matching function.
59 | void run(const MatchResult& result) override;
60 |
61 | private:
62 | /// Compares the parameters of a function with those expected in the query's
63 | /// `DeclarationData`.
64 | bool _matchParameters(const clang::ASTContext& context,
65 | const clang::FunctionDecl& function) const noexcept;
66 |
67 | /// Compares the contexts of a function with those expected in the query's
68 | /// `DeclarationData`.
69 | bool _matchContexts(const clang::FunctionDecl& function) const noexcept;
70 |
71 | /// The ongoing query object.
72 | Query& _query;
73 | };
74 |
75 | } // namespace DefinitionSearch
76 | } // namespace ClangExpand
77 |
78 | #endif // CLANG_EXPAND_DEFINITION_SEARCH_MATCH_HANDLER_HPP
79 |
--------------------------------------------------------------------------------
/include/clang-expand/definition-search/tool-factory.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_DEFINITION_SEARCH_TOOL_FACTORY_HPP
26 | #define CLANG_EXPAND_DEFINITION_SEARCH_TOOL_FACTORY_HPP
27 |
28 | // Clang includes
29 | #include
30 | #include
31 |
32 | // Standard includes
33 | #include
34 |
35 | namespace ClangExpand {
36 | struct Query;
37 | }
38 |
39 | namespace ClangExpand {
40 | namespace DefinitionSearch {
41 |
42 | /// \ingroup DefinitionSearch
43 | ///
44 | /// Simple factory class to create a parameterized `DefinitionSearch` tool.
45 | ///
46 | /// This class is required because the standard `newFrontendAction` function
47 | /// does not allow passing parameters to an action.
48 | class ToolFactory : public clang::tooling::FrontendActionFactory {
49 | public:
50 | /// Constructor, taking the file in which the declaration was found and the
51 | /// ongoing `Query`. This tool will skip the `declarationFile`, since its
52 | /// definition would already have been picked up during symbol search, if it
53 | /// had one.
54 | explicit ToolFactory(const std::string& declarationFile, Query& query);
55 |
56 | /// Creates the action of the definition search phase.
57 | /// \returns A `DefinitionSearch::Action`.
58 | clang::FrontendAction* create() override;
59 |
60 | private:
61 | /// The file in which the declaration was found.
62 | const std::string& _declarationFile;
63 |
64 | /// The ongoing `Query` object.
65 | Query& _query;
66 | };
67 | } // namespace DefinitionSearch
68 | } // namespace ClangExpand
69 |
70 | #endif // CLANG_EXPAND_DEFINITION_SEARCH_TOOL_FACTORY_HPP
71 |
--------------------------------------------------------------------------------
/include/clang-expand/options.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_OPTIONS_HPP
26 | #define CLANG_EXPAND_OPTIONS_HPP
27 |
28 | namespace ClangExpand {
29 | /// Options for a query.
30 | struct Options {
31 | /// Whether to include information about the function call in the result.
32 | bool wantsCall;
33 |
34 | /// Whether to include declaration information for the function.
35 | bool wantsDeclaration;
36 |
37 | /// Whether to include definition information for the function.
38 | bool wantsDefinition;
39 |
40 | /// Whether to include the rewritten funtcion body information for the
41 | /// function.
42 | bool wantsRewritten;
43 | };
44 | } // namespace ClangExpand
45 |
46 | #endif // CLANG_EXPAND_OPTIONS_HPP
47 |
--------------------------------------------------------------------------------
/include/clang-expand/result.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_RESULT_HPP
26 | #define CLANG_EXPAND_RESULT_HPP
27 |
28 | // Project includes
29 | #include "clang-expand/common/declaration-data.hpp"
30 | #include "clang-expand/common/definition-data.hpp"
31 | #include "clang-expand/common/range.hpp"
32 |
33 | // LLVM includes
34 | #include
35 |
36 | // Third party includes
37 | #include
38 |
39 | namespace llvm {
40 | class raw_ostream;
41 | }
42 |
43 | namespace ClangExpand {
44 | struct Query;
45 | /// Stores the result of a `Query`.
46 | ///
47 | /// Converting this structure to YAML gives the full (nested) output of
48 | /// clang-expand, including the call range, declaration and definition
49 | /// information.
50 | struct Result {
51 | /// Constructs a `Result` from a completed `Query`.
52 | ///
53 | /// If the query's options specify that the call range is requested, the query
54 | /// must contain `CallData`.
55 | explicit Result(Query&& query);
56 |
57 | /// Converts the `Result` to JSON.
58 | nlohmann::json toJson() const;
59 |
60 | /// The range of the entire function call.
61 | ///
62 | /// This is the range that has to be replaced when expanding the tall.
63 | llvm::Optional callRange;
64 |
65 | /// The declaration data of the call.
66 | llvm::Optional declaration;
67 |
68 | /// The definition data of the call.
69 | llvm::Optional definition;
70 | };
71 | } // namespace ClangExpand
72 |
73 | #endif // CLANG_EXPAND_RESULT_HPP
74 |
--------------------------------------------------------------------------------
/include/clang-expand/search.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_SEARCH_HPP
26 | #define CLANG_EXPAND_SEARCH_HPP
27 |
28 | /// \defgroup SymbolSearch
29 | /// \defgroup DefinitionSearch
30 |
31 | // Project includes
32 | #include "clang-expand/common/location.hpp"
33 |
34 | // Standard includes
35 | #include
36 | #include
37 |
38 | namespace clang {
39 | namespace tooling {
40 | class CompilationDatabase;
41 | }
42 | }
43 |
44 | namespace ClangExpand {
45 | struct Query;
46 | struct Result;
47 | struct Options;
48 |
49 | /// Represents a single run of the clang-expand tool.
50 | ///
51 | /// ## Overview
52 | ///
53 | /// A clang-expand invocation is split up into two major phases, that are in
54 | /// fact each one clang tool: "symbol search" and "definition search". The end
55 | /// goal of these two phases is to find the definition of a function (if so
56 | /// requested by the user) and maybe rewrite it.
57 | ///
58 | /// ### Symbol Search
59 | ///
60 | /// Symbol search is primarily concerned with finding the declaration of a
61 | /// function. It does so in three steps:
62 | ///
63 | /// 1. First, it finds the location of the function call in a representation
64 | /// understood by clang (i.e. as a `clang::SourceLocation`). This involves
65 | /// lexing the token "under the cursor" and convincing the source manager to
66 | /// hand over a `SourceLocation`.
67 | ///
68 | /// 2. Next, it finds the referenced call expression as a node in the
69 | /// AST. For this, a clang tool is spawned that walks the AST, looking for all
70 | /// function calls with the same name as we are looking for. If we find one that
71 | /// is at the location we want, we have our function call. This
72 | /// `clang::CallExpr` includes a multitude of rich semantic information about
73 | /// the call that we can further make use of.
74 | ///
75 | /// 3. The final step is extracting information about the
76 | /// declaration of the function. More precisely, we collect all the data we need
77 | /// so that subsequent phases of clang-expand can match function definitions
78 | /// back to this correct declaration. This data includes the name of the
79 | /// function, the parameter types and all *contexts* (namespaces or struct/class
80 | /// names) up to the `TranslationUnitDecl`.
81 | ///
82 | /// Along the way, we may pick up one of two different interesting pieces of
83 | /// information about the function call:
84 | ///
85 | /// 1. It may in fact not be a function call, but a *macro invocation*.
86 | /// If this is the case, we do something completely different than otherwise, as
87 | /// we need to hook into clang's preprocessing stage, i.e. we are not interested
88 | /// in the AST at all. Furthermore, the result of this will not be a
89 | /// declaration, but a definition.
90 | ///
91 | /// 2. If it is a function call, its declaration may also be a definition.
92 | /// In that case we can not only collect information about the declaration, but
93 | /// also the definition.
94 | ///
95 | /// In both of these cases, we have already found the definition of the function
96 | /// (or macro) in the symbol search phase. As the next phase is no longer
97 | /// required, the tool ends its execution at this point and the tool exits.
98 | ///
99 | /// Note that the world (C++) is unfortunately a lot more complex than it
100 | /// may seem from this description. Not all function calls are equal, since some
101 | /// may be constructor expressions, binary operators, method calls or function
102 | /// calls nested inside other statements. clang-expand tries to handle as many
103 | /// situations as possible and takes care to match for cases that it knows it
104 | /// can handle correctly and fails otherwise, rather than doing something stupid
105 | /// because it doesn't know better.
106 | ///
107 | /// ### Definition Search
108 | ///
109 | /// When the symbol search phase does not find a definition but only a
110 | /// declaration, this is most likely because the definition is in some other
111 | /// translation unit that would be linked in at link-time. It is then the
112 | /// responsibility of the definitition search stage to use the information
113 | /// gathered by symbol search about the function declaration to find the
114 | /// corresponding definition. This phase is again a clang tool of its own that
115 | /// takes in a set of source files and looks for matching functions in each
116 | /// file. For each function definition that matches the target declaration by
117 | /// name, its contexts and parameter types are compared to the target
118 | /// declaration.
119 | ///
120 | /// Once a definition is found, definition search will collect location and
121 | /// source information about it. Moreover, it is at this point that the function
122 | /// body can be inspected and rewritten to perform *expansion* of the original
123 | /// function call. This is done by initially collecting a *parameter map* in the
124 | /// declaration data that maps paremeter names to argument expressions (already
125 | /// during symbol search). When it comes to rewriting the body, the tool then
126 | /// taverses its AST subtree and looks for all references to parameters of the
127 | /// function. Each such reference is then replaced with the respective argument
128 | /// passed to the function call for that parameter. Additionally, if the
129 | /// function call is an assignment like `int x = f(42);`, return statements will
130 | /// be rewritten to assignments. This may not always be possible, for example
131 | /// when the type of the assigned variable is not default constructible but we
132 | /// find more than one return statement in the function body, meaning we cannot
133 | /// assign to the variable directly. clang-expand will fail with an appropriate
134 | /// error message in such a case.
135 | ///
136 | /// There are again many more edge cases and possibilities to handle than
137 | /// outlined here (courtesy of the flexibility of the C++ language). To sum up,
138 | /// however, the methods described above work for the following expressions:
139 | ///
140 | /// - simple function calls: `f(5);`
141 | /// - function calls as return statements: `return f(5);`
142 | /// - function calls with assignments: `int x = f(5);`
143 | /// - "external" method calls: `int x = o.f(); int y = p->f();`
144 | /// - "internal" method calls: `void X::f() { this->g(5); }`
145 | /// - operator overloads: `int x = ~o; return x == y;`
146 | /// - value initialization (constructor calls): `X x = X(5);`
147 | ///
148 | /// clang-expand tries also tries hard to be smart about how it handles variable
149 | /// declarations for expansions. In particular, if the expanded function body
150 | /// has only one return statements, that `return` will be rewritten to directly
151 | /// initialize the assigned variable. For example:
152 | ///
153 | /// ```.cpp
154 | /// int f(int x) {
155 | /// int y = 0;
156 | /// if (x > 10) {
157 | /// y += 1;
158 | /// }
159 | /// return x + y;
160 | /// }
161 | ///
162 | /// int z = f(5);
163 | /// ```
164 | ///
165 | /// will expand to:
166 | ///
167 | /// ```.cpp
168 | /// int y = 0;
169 | /// if (5 > 10) {
170 | /// y += 1;
171 | /// }
172 | /// int z = 5 + y;
173 | /// ```
174 | ///
175 | /// while a function with two return statements like:
176 | ///
177 | /// ```.cpp
178 | /// int f(int x) {
179 | /// if (rand() == 42) {
180 | /// return x;
181 | /// }
182 | /// return x + 1;
183 | /// }
184 | ///
185 | /// int z = f(5);
186 | /// ```
187 | ///
188 | /// will expand to:
189 | ///
190 | /// ```.cpp
191 | /// int z;
192 | /// if (rand() == 42) {
193 | /// z = 5;
194 | /// }
195 | /// z = 5 + 1;
196 | /// ```
197 | class Search {
198 | public:
199 | using CompilationDatabase = clang::tooling::CompilationDatabase;
200 | using SourceVector = std::vector;
201 |
202 | /// Constructs a new `Search` object with the `file`, `line` and `column`
203 | /// options from the command line.
204 | Search(const std::string& file, unsigned line, unsigned column);
205 |
206 | /// Runs the search on the given sources and with the given options.
207 | /// \returns A `Result`, ready to be printed to the console.
208 | Result run(CompilationDatabase& compilationDatabase,
209 | const SourceVector& sources,
210 | const Options& options);
211 |
212 | private:
213 | /// Performs the symbol search phase. Decorates the `Query` with
214 | /// `DeclarationData` and `CallData`, as well as possibly `DefinitionData`.
215 | void _symbolSearch(CompilationDatabase& compilationDatabase, Query& query);
216 |
217 | /// Performs the definition search phase. Decorates the `Query` with
218 | /// `DefinitionData`.
219 | void _definitionSearch(CompilationDatabase& compilationDatabase,
220 | const SourceVector& sources,
221 | Query& query);
222 |
223 | /// The target location, created from the constructor arguments.
224 | Location _location;
225 | };
226 | } // namespace ClangExpand
227 |
228 | #endif // CLANG_EXPAND_SEARCH_HPP
229 |
--------------------------------------------------------------------------------
/include/clang-expand/symbol-search/action.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_SYMBOL_SEARCH_ACTION_HPP
26 | #define CLANG_EXPAND_SYMBOL_SEARCH_ACTION_HPP
27 |
28 | // Project includes
29 | #include "clang-expand/common/location.hpp"
30 |
31 | // Clang includes
32 | #include
33 | #include
34 |
35 | // Standard includes
36 | #include
37 | #include
38 |
39 | namespace clang {
40 | class CompilerInstance;
41 | class ASTConsumer;
42 | }
43 |
44 | namespace llvm {
45 | class StringRef;
46 | }
47 |
48 | namespace ClangExpand {
49 | struct Query;
50 | }
51 |
52 | namespace ClangExpand {
53 | namespace SymbolSearch {
54 |
55 | /// \ingroup SymbolSearch
56 | ///
57 | /// The `SymbolSearch::Action` class has a major responsibility at the very
58 | /// beginning of the entire `clang-expand` tool.
59 | ///
60 | /// It does three main things:
61 | ///
62 | /// 1. Translates the location that was specified when invoking clang-expand to
63 | /// a `clang::SourceLocation`, so that it can be used to interact with the rest
64 | /// of clang in further stages of symbol search.
65 | /// 2. Installs preprocessor callbacks to facilitate the part of clang-expand
66 | /// dealing with macros.
67 | /// 3. Returns a `SymbolSearch::Consumer` to continue the processing pipeline.
68 | ///
69 | /// Step (1) is one of the more fragile stages of clang-expand as we are dealing
70 | /// with raw (stupid) lexing. Once we have an `ASTConsumer`, things are a bit
71 | /// smoother as we have actual representations inside the AST.
72 | class Action : public clang::ASTFrontendAction {
73 | public:
74 | using super = clang::ASTFrontendAction;
75 | using ASTConsumerPointer = std::unique_ptr;
76 |
77 | /// Constructor, taking the location at which to look for a function call and
78 | /// the ongoing `Query` object.
79 | Action(Location targetLocation, Query& query);
80 |
81 | /// Attempts to translate the `targetLocation` to a `clang::SourceLocation`
82 | /// and install preprocessor hooks for macros.
83 | bool BeginSourceFileAction(clang::CompilerInstance& compiler,
84 | llvm::StringRef filename) override;
85 |
86 | /// \returns a `SymbolSearch::Consumer`.
87 | ASTConsumerPointer CreateASTConsumer(clang::CompilerInstance& compiler,
88 | llvm::StringRef filename) override;
89 |
90 | private:
91 | /// Given a `clang::CompilerInstance`, installs appropriate preprocessor
92 | /// hooks for macro search (looking for macros with the name of the target
93 | /// function) with the `CompilerInstance`.
94 | void _installMacroFacilities(clang::CompilerInstance& compiler) const;
95 |
96 | /// The spelling (name/string) of the token under the cursor.
97 | std::string _spelling;
98 |
99 | /// The ongoing `Query` object.
100 | Query& _query;
101 |
102 | /// The location under the user's cursor (or what clang-expand was invoked
103 | /// with).
104 | Location _targetLocation;
105 |
106 | /// The target location, translated to a `clang::SourceLocation` once we have
107 | /// found it. We have to store it as a member to be able to pass it to the
108 | /// `Consumer` inside `CreateASTConsumer`
109 | clang::SourceLocation _callLocation;
110 | };
111 |
112 | } // namespace SymbolSearch
113 | } // namespace ClangExpand
114 |
115 | #endif // CLANG_EXPAND_SYMBOL_SEARCH_ACTION_HPP
116 |
--------------------------------------------------------------------------------
/include/clang-expand/symbol-search/consumer.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_SYMBOL_SEARCH_CONSUMER_HPP
26 | #define CLANG_EXPAND_SYMBOL_SEARCH_CONSUMER_HPP
27 |
28 | // Project includes
29 | #include "clang-expand/symbol-search/match-handler.hpp"
30 |
31 | // Clang includes
32 | #include
33 |
34 | // Standard includes
35 | #include
36 |
37 | namespace clang {
38 | class ASTContext;
39 | class SourceLocation;
40 | }
41 |
42 | namespace ClangExpand {
43 | struct Query;
44 | }
45 |
46 | namespace ClangExpand {
47 | namespace SymbolSearch {
48 |
49 | /// \ingroup SymbolSearch
50 | ///
51 | /// The `SymbolSearch::Consumer` is responsible for creating an appropriate
52 | /// `ASTMatchers` expression and dispatching an AST visitor using clang's
53 | /// ASTMatcher's library. For any match, our `SymbolSearch::MatchHandler` will
54 | /// be invoked.
55 | ///
56 | /// The `ASTMatchers` expression we create is quite complex, as it has to match
57 | /// functions, methods, constructors and all derivatives thereof (though we get
58 | /// those for free). The full (lisp-commented) matcher looks like this:
59 | ///
60 | /// ```
61 | /// expr(anyOf( ;; any expression
62 | /// callExpr(anyOf( ;; that is a call expression
63 | /// hasDescendant(declRefExpr( ;; that is a function reference
64 | /// ;; with the name we want
65 | /// hasDeclaration(functionDecl(hasName(spelling)).bind("fn")))
66 | /// .bind("ref")),
67 | /// hasDescendant(memberExpr( ;; or a method reference
68 | /// ;; with the name we want
69 | /// hasDeclaration(cxxMethodDecl(hasName(spelling)).bind("fn")))
70 | /// .bind("member"))))
71 | /// .bind("call"),
72 | /// cxxConstructExpr( ;; or is not a call expression, but a construction
73 | /// hasDeclaration(
74 | /// cxxConstructorDecl(
75 | /// hasName(spelling), ;; with the name we want
76 | /// isUserProvided()) ;; and is not compiler-generated
77 | /// .bind("fn")))
78 | /// .bind("construct")));
79 | /// ```
80 | class Consumer : public clang::ASTConsumer {
81 | public:
82 | /// Constructor.
83 | Consumer(const clang::SourceLocation& invocationLocation,
84 | std::string callSpelling,
85 | Query& query);
86 |
87 | /// Creates an appropriate match expression and dispatches the
88 | /// `SymbolSearch::MatchHandler`
89 | void HandleTranslationUnit(clang::ASTContext& context) override;
90 |
91 | private:
92 | /// The spelling (string representation) of the invoked function.
93 | const std::string _callSpelling;
94 |
95 | /// Our callback class for ASTMatcher matches.
96 | MatchHandler _matchHandler;
97 | };
98 |
99 | } // namespace SymbolSearch
100 | } // namespace ClangExpand
101 |
102 | #endif // CLANG_EXPAND_SYMBOL_SEARCH_CONSUMER_HPP
103 |
--------------------------------------------------------------------------------
/include/clang-expand/symbol-search/macro-search.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_SYMBOL_SEARCH_PREPROCESSOR_HOOKS_HPP
26 | #define CLANG_EXPAND_SYMBOL_SEARCH_PREPROCESSOR_HOOKS_HPP
27 |
28 | // Project includes
29 | #include "clang-expand/common/canonical-location.hpp"
30 |
31 | // Clang includes
32 | #include
33 | #include
34 |
35 | // LLVM includes
36 | #include
37 |
38 | // Standard includes
39 | #include
40 |
41 | namespace clang {
42 | class LangOptions;
43 | class CompilerInstance;
44 | class MacroArgs;
45 | class MacroDefinition;
46 | class MacroInfo;
47 | class Preprocessor;
48 | class SourceManager;
49 | class Token;
50 | } // namespace clang
51 |
52 | namespace llvm {
53 | template
54 | class SmallString;
55 | }
56 |
57 | namespace ClangExpand {
58 | struct Query;
59 | } // namespace ClangExpand
60 |
61 | namespace ClangExpand {
62 | namespace SymbolSearch {
63 |
64 | /// Class responsible for inspecting macros during symbol search.
65 | ///
66 | /// For a given invocation `f(x)`, we don't know from the raw source text if `f`
67 | /// is a function or a macro. Also, at the point where we have the chance to
68 | /// hook into the preprocessor (inside the `SymbolSearch::Action`), we don't
69 | /// yet have an AST, so we cannot find this information out. As such, we need to
70 | /// hook into the prepocessing stage and look out for macro invocations. If
71 | /// there is one such invocation whose location matches the cursor, we have
72 | /// determined that the function call is actually a macro expansion and we can
73 | /// process it straight away into a `DefinitionData` object, since macros must
74 | /// always be defined on the spot. Since translation units are preprocessed
75 | /// anyway irrespective of whether or not we need something from this stage,
76 | /// this functioncality incurs very little performance overhead.
77 | struct MacroSearch : public clang::PPCallbacks {
78 | public:
79 | /// Constructor.
80 | MacroSearch(clang::CompilerInstance& compiler,
81 | const clang::SourceLocation& location,
82 | Query& query);
83 |
84 | /// Hook for any macro expansion. A macro expansion will either be a
85 | /// function-macro call like `f(x)`, or simply an object-macro expansion like
86 | /// `NULL` (which is `(void*)0`).
87 | void MacroExpands(const clang::Token& macroNameToken,
88 | const clang::MacroDefinition& macroDefinition,
89 | clang::SourceRange range,
90 | const clang::MacroArgs* macroArgs) override;
91 |
92 | private:
93 | using ParameterMap = llvm::StringMap>;
94 |
95 | /// Rewrites a function-macro contents using the arguments it was invoked
96 | /// with. This function identifies `#` and `##` stringification and
97 | /// concatenation operators and deals with them correctly.
98 | std::string _rewriteMacro(const clang::MacroInfo& info,
99 | const ParameterMap& mapping);
100 |
101 | /// Creates a mapping from parameter names to argument expressions.
102 | ParameterMap _createParameterMap(const clang::MacroInfo& info,
103 | const clang::MacroArgs& arguments);
104 |
105 | /// Gets the spelling (string representation) of a token using the
106 | /// preprocessor.
107 | std::string _getSpelling(const clang::Token& token) const; // NOLINT
108 |
109 | /// The current `clang::SourceManager` from the compiler.
110 | clang::SourceManager& _sourceManager;
111 |
112 | /// The current `clang::LangOptions` from the compiler.
113 | const clang::LangOptions& _languageOptions;
114 |
115 | /// The `clang::Preprocessor` instance we operate on.
116 | clang::Preprocessor& _preprocessor;
117 |
118 | /// The canonical location of the (function) call that we are targeting.
119 | const CanonicalLocation _targetLocation;
120 |
121 | /// The ongoing `Query` object.
122 | Query& _query;
123 | };
124 |
125 | } // namespace SymbolSearch
126 | } // namespace ClangExpand
127 |
128 | #endif // CLANG_EXPAND_SYMBOL_SEARCH_PREPROCESSOR_HOOKS_HPP
129 |
--------------------------------------------------------------------------------
/include/clang-expand/symbol-search/match-handler.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_SYMBOL_SEARCH_MATCH_HANDLER_HPP
26 | #define CLANG_EXPAND_SYMBOL_SEARCH_MATCH_HANDLER_HPP
27 |
28 | // Clang includes
29 | #include
30 |
31 | namespace clang {
32 | class SourceLocation;
33 | }
34 |
35 | namespace ClangExpand {
36 | struct Query;
37 | }
38 |
39 | namespace ClangExpand {
40 | namespace SymbolSearch {
41 |
42 | /// \ingroup SymbolSearch
43 | ///
44 | /// Handles candidate functions in the source.
45 | ///
46 | /// This class does the heaviest lifting of any components inside clang-expand
47 | /// as it has to handle all aspects of:
48 | /// 1. Checking for a function call expression that matches the ASTMatchers
49 | /// expression from the `SymbolSearch::Consumer` (i.e. with the correct name) if
50 | /// that call location is at the right place (under the user's cursor).
51 | /// 2. Verifying if it is safe to expand the function call wherever it is in the
52 | /// source. For example, it is not safe to expand a function call inside another
53 | /// function call.
54 | /// 3. Collecting `CallData`, including the source extent of the call and
55 | /// assignee of any return value.
56 | /// 4. Collecting `DeclarationData`, i.e. as much information as possible to
57 | /// serialize our knowledge for later use in the definition search phase.
58 | /// 5. If the declaration is in fact also a definition, collecting
59 | /// `DefinitionData`.
60 | class MatchHandler : public clang::ast_matchers::MatchFinder::MatchCallback {
61 | public:
62 | using MatchResult = clang::ast_matchers::MatchFinder::MatchResult;
63 |
64 | /// Constructor.
65 | explicit MatchHandler(const clang::SourceLocation& targetLocation,
66 | Query& query);
67 |
68 | /// Runs the `MatchHandler` for a matching expression.
69 | void run(const MatchResult& result) override;
70 |
71 | private:
72 | /// The target location of the function call.
73 | const clang::SourceLocation& _targetLocation;
74 |
75 | /// The ongoing `Query` object.
76 | Query& _query;
77 | };
78 |
79 | } // namespace SymbolSearch
80 | } // namespace ClangExpand
81 |
82 | #endif // CLANG_EXPAND_SYMBOL_SEARCH_MATCH_HANDLER_HPP
83 |
--------------------------------------------------------------------------------
/include/clang-expand/symbol-search/tool-factory.hpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | #ifndef CLANG_EXPAND_SYMBOL_SEARCH_TOOL_FACTORY_HPP
26 | #define CLANG_EXPAND_SYMBOL_SEARCH_TOOL_FACTORY_HPP
27 |
28 | // Clang includes
29 | #include
30 | #include
31 |
32 | namespace ClangExpand {
33 | struct Query;
34 | struct Location;
35 | }
36 |
37 | namespace ClangExpand {
38 | namespace SymbolSearch {
39 |
40 | /// \ingroup SymbolSearch
41 | ///
42 | /// Simple factory class to create a parameterized `SymbolSearch` tool.
43 | ///
44 | /// This class is required because the standard `newFrontendAction` function
45 | /// does not allow passing parameters to an action.
46 | class ToolFactory : public clang::tooling::FrontendActionFactory {
47 | public:
48 | /// Constructor, taking the location the user invoked clang-expand with and
49 | /// the fresh `Query` object.
50 | explicit ToolFactory(const Location& _targetLocation, Query& query);
51 |
52 | /// Creates the action of the symbol search phase.
53 | /// \returns A `SymbolSearch::Action`.
54 | clang::FrontendAction* create() override;
55 |
56 | private:
57 | /// The location at which the user invoked clang-expand.
58 | const Location& _targetLocation;
59 |
60 | /// The newly created `Query` object.
61 | Query& _query;
62 | };
63 | } // namespace SymbolSearch
64 | } // namespace ClangExpand
65 |
66 | #endif // CLANG_EXPAND_SYMBOL_SEARCH_TOOL_FACTORY_HPP
67 |
--------------------------------------------------------------------------------
/source/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | ########################################
2 | # SOURCES
3 | ########################################
4 |
5 | set(CLANG_EXPAND_SOURCES
6 | common/assignee-data.cpp
7 | common/call-data.cpp
8 | common/canonical-location.cpp
9 | common/definition-data.cpp
10 | common/declaration-data.cpp
11 | common/definition-rewriter.cpp
12 | common/location.cpp
13 | common/offset.cpp
14 | common/range.cpp
15 | common/routines.cpp
16 | definition-search/action.cpp
17 | definition-search/consumer.cpp
18 | definition-search/match-handler.cpp
19 | definition-search/tool-factory.cpp
20 | result.cpp
21 | search.cpp
22 | symbol-search/action.cpp
23 | symbol-search/consumer.cpp
24 | symbol-search/macro-search.cpp
25 | symbol-search/match-handler.cpp
26 | symbol-search/tool-factory.cpp
27 | )
28 |
29 | ########################################
30 | # TARGET
31 | ########################################
32 |
33 | add_library(clang-expand-library STATIC ${CLANG_EXPAND_SOURCES})
34 |
--------------------------------------------------------------------------------
/source/common/assignee-data.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/common/assignee-data.hpp"
27 |
28 | // LLVM includes
29 | #include
30 | #include
31 | #include
32 |
33 | // Standard includes
34 | #include
35 | #include
36 | #include
37 |
38 | namespace ClangExpand {
39 |
40 | AssigneeData::Type::Type(std::string name_,
41 | bool isDefaultConstructible_) noexcept
42 | : name(std::move(name_)), isDefaultConstructible(isDefaultConstructible_) {
43 | }
44 |
45 | AssigneeData::Builder::Builder(AssigneeData&& assignee)
46 | : _assignee(std::move(assignee)) {
47 | }
48 |
49 | AssigneeData::Builder&
50 | AssigneeData::Builder::name(const llvm::StringRef& name) {
51 | _assignee.name = name.rtrim();
52 | return *this;
53 | }
54 |
55 | AssigneeData::Builder& AssigneeData::Builder::type(
56 | const llvm::StringRef& name, bool isDefaultConstructible) {
57 | _assignee.type.emplace(name, isDefaultConstructible);
58 | return *this;
59 | }
60 |
61 | AssigneeData::Builder& AssigneeData::Builder::op(const llvm::StringRef& op) {
62 | _assignee.op = op;
63 | return *this;
64 | }
65 |
66 | AssigneeData AssigneeData::Builder::build() {
67 | return std::move(_assignee);
68 | }
69 |
70 | bool AssigneeData::isDefaultConstructible() const noexcept {
71 | return !type.hasValue() || type->isDefaultConstructible;
72 | }
73 |
74 | std::string AssigneeData::toAssignment(bool withType) const {
75 | if (withType) {
76 | assert(type.hasValue() &&
77 | "Requested assignee string with type, but have no type");
78 | return (llvm::Twine(type->name) + " " + name + " " + op).str();
79 | }
80 | return (llvm::Twine(name) + " " + op).str();
81 | }
82 |
83 | std::string AssigneeData::toDeclaration() const {
84 | assert(type.hasValue() && "Requested assignee declaration, but have no type");
85 | return (llvm::Twine(type->name) + " " + name + ";").str();
86 | }
87 |
88 | } // namespace ClangExpand
89 |
--------------------------------------------------------------------------------
/source/common/call-data.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/common/call-data.hpp"
27 |
28 | // LLVM includes
29 | #include
30 |
31 | // Standard includes
32 | #include
33 |
34 | namespace ClangExpand {
35 | CallData::CallData(AssigneeData&& assignee, Range&& extent_)
36 | : assignee(std::move(assignee)), extent(extent_) {
37 | }
38 |
39 | CallData::CallData(Range&& extent_) : extent(extent_) {
40 | }
41 |
42 | bool CallData::requiresDeclaration() const noexcept {
43 | return assignee.hasValue() && assignee->type.hasValue();
44 | }
45 |
46 | } // namespace ClangExpand
47 |
--------------------------------------------------------------------------------
/source/common/canonical-location.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/common/canonical-location.hpp"
27 |
28 | // Clang includes
29 | #include
30 |
31 | // Standard includes
32 | #include
33 |
34 | namespace ClangExpand {
35 | CanonicalLocation::CanonicalLocation(
36 | const clang::SourceLocation& location,
37 | const clang::SourceManager& sourceManager) {
38 | const auto decomposed = sourceManager.getDecomposedLoc(location);
39 | file = sourceManager.getFileEntryForID(decomposed.first);
40 | offset = decomposed.second;
41 | }
42 |
43 | bool CanonicalLocation::operator==(const CanonicalLocation& other) const
44 | noexcept {
45 | return this->file == other.file && this->offset == other.offset;
46 | }
47 |
48 | bool CanonicalLocation::operator!=(const CanonicalLocation& other) const
49 | noexcept {
50 | return !(*this == other);
51 | }
52 | } // namespace ClangExpand
53 |
--------------------------------------------------------------------------------
/source/common/declaration-data.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/common/declaration-data.hpp"
27 | #include "clang-expand/common/location.hpp"
28 |
29 | // Third party includes
30 | #include
31 |
32 | // Standard includes
33 | #include
34 | #include
35 |
36 | namespace ClangExpand {
37 | DeclarationData::DeclarationData(std::string name_, Location location_)
38 | : name(std::move(name_)), location(std::move(location_)) {
39 | }
40 |
41 | nlohmann::json DeclarationData::toJson() const {
42 | // clang-format off
43 | return {
44 | {"location", location.toJson()},
45 | {"name", name},
46 | {"text", text}
47 | };
48 | // clang-format on
49 | }
50 | } // namespace ClangExpand
51 |
--------------------------------------------------------------------------------
/source/common/definition-data.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/common/definition-data.hpp"
27 | #include "clang-expand/common/assignee-data.hpp"
28 | #include "clang-expand/common/declaration-data.hpp"
29 | #include "clang-expand/common/definition-rewriter.hpp"
30 | #include "clang-expand/common/location.hpp"
31 | #include "clang-expand/common/query.hpp"
32 |
33 | // Third party includes
34 | #include
35 |
36 | // Clang includes
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include "clang-expand/common/call-data.hpp"
43 | #include "clang-expand/options.hpp"
44 |
45 | // LLVM includes
46 | #include
47 | #include
48 | #include
49 | #include
50 |
51 | // Standard includes
52 | #include
53 | #include
54 | #include
55 | #include
56 |
57 | namespace ClangExpand {
58 | namespace {
59 | /// Removes all excess whitespace around the string, and from the start of each
60 | /// line. This is necessary so that the body of the function can be returned
61 | /// without any extra padding on the left, as it would normally have at least
62 | /// one level of indenting if simply cut out of a real function.
63 | ///
64 | /// For example, given this function that we want to rewrite:
65 | ///
66 | /// ```.cpp
67 | /// bool f(int x) {
68 | /// int y = 5;
69 | /// if (x + y > 5) {
70 | /// return true;
71 | /// }
72 | /// return false;
73 | /// }
74 | /// ```
75 | ///
76 | /// We may extract the body first as such:
77 | ///
78 | /// ```.cpp
79 | /// int y = 5;
80 | /// if (x + y > 5) {
81 | /// return true;
82 | /// }
83 | /// return false;
84 | /// ```
85 | /// and this function then turns it into this normalized snippet:
86 | ///
87 | /// ```.cpp
88 | /// int y = 5;
89 | /// if (x + y > 5) {
90 | /// return true;
91 | /// }
92 | /// return false;
93 | /// ```
94 | ///
95 | /// Note how only the first level of indentation is removed. Further levels are
96 | /// maintained as expected.
97 | ///
98 | std::string withoutIndentation(std::string text) {
99 | // clang-format off
100 | static const std::regex whitespacePattern(
101 | R"(^\s*\n(\s+)\S|(\s+))", std::regex::ECMAScript | std::regex::optimize);
102 | // clang-format on
103 |
104 | std::smatch match;
105 | if (!std::regex_search(text, match, whitespacePattern)) {
106 | return text;
107 | }
108 |
109 | assert(match[1].matched || match[2].matched);
110 | const std::string excess = match[1].matched ? match.str(1) : match.str(2);
111 |
112 | // C++ regex doesn't have a multiline option (or at least clang doesn't have
113 | // one yet, should be in C++17), so we need to hack.
114 | const std::regex excessPattern("\\n" + excess, std::regex::optimize);
115 |
116 | const auto trimmed = llvm::StringRef(text).trim().str();
117 | return std::regex_replace(trimmed, excessPattern, "\n");
118 | }
119 |
120 | /// Returns the fully processed rewritten text of a function body.
121 | std::string getRewrittenText(clang::Stmt* body,
122 | const Query& query,
123 | clang::ASTContext& context,
124 | clang::Rewriter& rewriter) {
125 | const auto& map = query.declaration->parameterMap;
126 |
127 | assert(query.call && "Should have call data when rewriting the definition");
128 |
129 | DefinitionRewriter definitionRewriter(rewriter, map, *query.call, context);
130 | definitionRewriter.TraverseStmt(body);
131 |
132 | bool shouldDeclare = false;
133 | if (query.call->assignee) {
134 | shouldDeclare = definitionRewriter.rewriteReturnsToAssignments(*body);
135 | }
136 |
137 | const auto afterBrace = body->getLocStart().getLocWithOffset(+1);
138 | const auto beforeBrace = body->getLocEnd().getLocWithOffset(-1);
139 | const clang::SourceRange range(afterBrace, beforeBrace);
140 |
141 | auto text = withoutIndentation(rewriter.getRewrittenText(range));
142 |
143 | if (shouldDeclare) {
144 | const std::string declaration = query.call->assignee->toDeclaration();
145 | return (declaration + llvm::Twine("\n") + text).str();
146 | }
147 |
148 | return text;
149 | }
150 | } // namespace
151 |
152 | DefinitionData DefinitionData::Collect(const clang::FunctionDecl& function,
153 | clang::ASTContext& context,
154 | const Query& query) {
155 | const auto& sourceManager = context.getSourceManager();
156 | Location location(function.getLocation(), sourceManager);
157 |
158 | assert(function.hasBody() &&
159 | "Function should have a body to collect definition");
160 | auto* body = llvm::cast(function.getBody());
161 |
162 | if (body->body_empty()) return {location, "", ""};
163 |
164 | clang::Rewriter rewriter(context.getSourceManager(), context.getLangOpts());
165 |
166 | std::string original;
167 | if (query.options.wantsDefinition) {
168 | const clang::SourceRange entireFunction(function.getSourceRange());
169 | original = rewriter.getRewrittenText(entireFunction);
170 | }
171 |
172 | std::string rewritten;
173 | if (query.options.wantsRewritten) {
174 | rewritten = getRewrittenText(body, query, context, rewriter);
175 | }
176 |
177 | return {std::move(location), std::move(original), std::move(rewritten)};
178 | }
179 |
180 | nlohmann::json DefinitionData::toJson() const {
181 | // clang-format off
182 | nlohmann::json json = {
183 | {"location", location.toJson()},
184 | {"macro", isMacro}
185 | };
186 | // clang-format on
187 |
188 | if (!original.empty()) {
189 | json["text"] = original;
190 | }
191 |
192 | if (!rewritten.empty()) {
193 | json["rewritten"] = rewritten;
194 | }
195 |
196 | return json;
197 | }
198 |
199 | } // namespace ClangExpand
200 |
--------------------------------------------------------------------------------
/source/common/definition-rewriter.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/common/definition-rewriter.hpp"
27 | #include "clang-expand/common/assignee-data.hpp"
28 | #include "clang-expand/common/call-data.hpp"
29 | #include "clang-expand/common/routines.hpp"
30 |
31 | // Clang includes
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 |
42 | // LLVM includes
43 | #include
44 | #include
45 | #include
46 | #include
47 | #include
48 | #include
49 |
50 | // Standard includes
51 | #include
52 | #include
53 |
54 |
55 | namespace ClangExpand {
56 | namespace {
57 |
58 | /// Dies with an error message warning that the function could not be expanded
59 | /// because the assigned type is not default constructible (like `int&`).
60 | [[noreturn]] void dieBecauseNotDefaultConstructible() {
61 | Routines::error(
62 | "Could not expand function because "
63 | "assignee is not default-constructible");
64 | }
65 |
66 | /// Tries to get the parent of a node as the given type `T`, or else errors and
67 | /// dies.
68 | template
69 | const T* tryToGetParentOrDie(clang::ASTContext& context, const Node& node) {
70 | if (const auto* parent = context.getParents(node).begin()) {
71 | if (const auto* asType = parent->template get()) {
72 | return asType;
73 | }
74 | }
75 |
76 | dieBecauseNotDefaultConstructible();
77 | }
78 |
79 | /// Ensures that a `ReturnStmt` would allow default construction of a variable.
80 | /// This is the case if this is a top-level `return`, i.e. whose parent is the
81 | /// `CompoundStmt` of a function.
82 | void ensureReturnAllowsDefaultConstruction(
83 | clang::ASTContext& context, const clang::ReturnStmt& returnStatement) {
84 | const auto* compound =
85 | tryToGetParentOrDie(context, returnStatement);
86 | tryToGetParentOrDie(context, *compound);
87 | }
88 | } // namespace
89 |
90 | DefinitionRewriter::DefinitionRewriter(clang::Rewriter& rewriter,
91 | const ParameterMap& parameterMap,
92 | const CallData& call,
93 | clang::ASTContext& context)
94 | : _rewriter(rewriter)
95 | , _parameterMap(parameterMap)
96 | , _call(call)
97 | , _context(context) {
98 | }
99 |
100 | bool DefinitionRewriter::VisitStmt(clang::Stmt* statement) {
101 | const auto* nonType =
102 | llvm::dyn_cast(statement);
103 | if (nonType) {
104 | _rewriteNonTypeTemplateParameterExpression(*nonType);
105 | }
106 |
107 | if (llvm::isa(statement)) {
108 | if (auto* rtn = llvm::dyn_cast(statement)) {
109 | _recordReturn(*rtn, _call);
110 | return true;
111 | }
112 | }
113 |
114 | if (const auto* member = llvm::dyn_cast(statement)) {
115 | if (llvm::isa(member->getBase()->IgnoreImplicit())) {
116 | _rewriteMemberExpression(*member);
117 | }
118 | }
119 |
120 | const auto* reference = llvm::dyn_cast(statement);
121 | if (!reference) return true;
122 |
123 | const auto* declaration =
124 | llvm::dyn_cast(reference->getDecl());
125 | if (!declaration) return true;
126 |
127 | const auto name = declaration->getName();
128 |
129 | auto iterator = _parameterMap.find(name);
130 | if (iterator != _parameterMap.end()) {
131 | const auto& argument = iterator->getValue();
132 | bool error = _rewriter.ReplaceText(reference->getSourceRange(), argument);
133 | (void)error;
134 | assert(!error && "Error replacing text in definition");
135 | }
136 |
137 | return true;
138 | }
139 |
140 | bool DefinitionRewriter::VisitTypeLoc(clang::TypeLoc typeLocation) {
141 | const auto* templateType =
142 | llvm::dyn_cast(typeLocation.getType());
143 | if (!templateType) return true;
144 |
145 | const auto original =
146 | templateType->getReplacedParameter()->desugar().getAsString();
147 | const auto start = typeLocation.getLocStart();
148 | const auto end =
149 | typeLocation.getLocStart().getLocWithOffset(original.length() - 1);
150 |
151 | const auto replacement = templateType->getReplacementType().getAsString();
152 | _rewriter.ReplaceText({start, end}, replacement);
153 |
154 | return true;
155 | }
156 |
157 | bool DefinitionRewriter::rewriteReturnsToAssignments(const clang::Stmt& body) {
158 | assert(_call.assignee.hasValue() &&
159 | "Cannot rewrite returns to assignments without an assignee");
160 | assert(!_returnLocations.empty() &&
161 | "Assigning to a function call that doesn't return?");
162 |
163 | if (_returnLocations.size() == 1) {
164 | _rewriteReturn(_returnLocations.front(), _call.assignee->toAssignment());
165 | return false;
166 | }
167 |
168 | assert(_call.assignee->isDefaultConstructible());
169 |
170 | for (const auto& location : _returnLocations) {
171 | _rewriteReturn(location, _call.assignee->toAssignment(/*withType=*/false));
172 | }
173 |
174 | return _call.requiresDeclaration();
175 | }
176 |
177 | void DefinitionRewriter::_recordReturn(const clang::ReturnStmt& returnStatement,
178 | const CallData& call) {
179 | if (!call.assignee.hasValue()) return;
180 | if (!call.assignee->isDefaultConstructible()) {
181 | // If we already found a return statement on the top level of the function,
182 | // then die. This is a super-duper edge case when the code has two return
183 | // statements on the top function level (making everything underneath the
184 | // first return dead code).
185 | if (_returnLocations.empty()) {
186 | ensureReturnAllowsDefaultConstruction(_context, returnStatement);
187 | } else {
188 | dieBecauseNotDefaultConstructible();
189 | }
190 | }
191 |
192 | auto location = returnStatement.getSourceRange().getBegin();
193 | _returnLocations.emplace_back(location); // trivially-copyable
194 | }
195 |
196 | void DefinitionRewriter::_rewriteReturn(const clang::SourceLocation& begin,
197 | const std::string& replacement) {
198 | static constexpr auto lengthOfTheWordReturn = 6;
199 |
200 | const auto end = begin.getLocWithOffset(lengthOfTheWordReturn);
201 | const bool error = _rewriter.ReplaceText({begin, end}, replacement);
202 | assert(!error && "Error replacing return statement in definition");
203 | (void)error;
204 | }
205 |
206 | void DefinitionRewriter::_rewriteMemberExpression(
207 | const clang::MemberExpr& member) {
208 | // If the base is empty, this means (should mean) that this function was an
209 | // implicit access, e.g. calling `f()` inside the class that declares `f()`.
210 | // Therefore all member expressions will already be valid and don't need any
211 | // change anyway (i.e. referencing the field `x` by `x` will be fine).
212 | if (_call.base.empty()) return;
213 | if (_rewrittenMembers.count(&member)) return;
214 |
215 | if (member.isImplicitAccess()) {
216 | _rewriter.InsertText(member.getMemberLoc(), _call.base);
217 | } else {
218 | // Gobble up any kind of 'this->' statement or qualifier (e.g. super::x,
219 | // where 'super' is typedef for the base class, i.e. still an implicit
220 | // access).
221 | const auto start = member.getLocStart();
222 | const auto end = member.getMemberLoc().getLocWithOffset(-1);
223 | _rewriter.ReplaceText({start, end}, _call.base);
224 | }
225 |
226 | // I've encountered cases where the exact same member will match twice.
227 |
228 | _rewrittenMembers.insert(&member);
229 | }
230 |
231 | void DefinitionRewriter::_rewriteNonTypeTemplateParameterExpression(
232 | const clang::SubstNonTypeTemplateParmExpr& nonType) {
233 | const auto* expression =
234 | nonType.getReplacement()->IgnoreImplicit()->IgnoreCasts();
235 | const auto* integer = llvm::dyn_cast(expression);
236 | if (!integer) return;
237 |
238 | const bool isUnsigned =
239 | nonType.getParameter()->getType().getTypePtr()->isUnsignedIntegerType();
240 | const auto replacement =
241 | integer->getValue().toString(10, /*Signed=*/!isUnsigned);
242 |
243 | const auto range = nonType.getSourceRange();
244 | const bool error = _rewriter.ReplaceText(range, replacement);
245 | assert(!error && "Error replacing non-type template parameter expression");
246 | (void)error;
247 | }
248 |
249 | } // namespace ClangExpand
250 |
--------------------------------------------------------------------------------
/source/common/location.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/common/location.hpp"
27 |
28 | // Third party includes
29 | #include
30 |
31 | // Clang includes
32 | #include
33 |
34 | // LLVM includes
35 | #include
36 |
37 | namespace ClangExpand {
38 | Location::Location(const clang::SourceLocation& location,
39 | const clang::SourceManager& sourceManager)
40 | : filename(sourceManager.getFilename(location))
41 | , offset(location, sourceManager) {
42 | }
43 |
44 | Location::Location(const llvm::StringRef& filename_,
45 | unsigned line,
46 | unsigned column)
47 | : filename(filename_), offset{line, column} {
48 | }
49 |
50 | nlohmann::json Location::toJson() const {
51 | // clang-format off
52 | return {
53 | {"filename", filename},
54 | {"offset", offset.toJson()}
55 | };
56 | // clang-format on
57 | }
58 |
59 | } // namespace ClangExpand
60 |
--------------------------------------------------------------------------------
/source/common/offset.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/common/offset.hpp"
27 |
28 | // Third party includes
29 | #include
30 |
31 | // Clang includes
32 | #include
33 |
34 | namespace ClangExpand {
35 | Offset::Offset(const clang::SourceLocation& location,
36 | const clang::SourceManager& sourceManager)
37 | : line(sourceManager.getSpellingLineNumber(location))
38 | , column(sourceManager.getSpellingColumnNumber(location)) {
39 | }
40 |
41 | Offset::Offset(unsigned line_, unsigned column_)
42 | : line(line_), column(column_) {
43 | }
44 |
45 | nlohmann::json Offset::toJson() const {
46 | // clang-format off
47 | return {
48 | {"line", line},
49 | {"column", column}
50 | };
51 | // clang-format on
52 | }
53 |
54 | } // namespace ClangExpand
55 |
--------------------------------------------------------------------------------
/source/common/range.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/common/range.hpp"
27 |
28 | // Third party includes
29 | #include
30 |
31 | // Clang includes
32 | #include
33 | #include
34 |
35 | namespace ClangExpand {
36 | Range::Range(const clang::SourceRange& range,
37 | const clang::SourceManager& sourceManager)
38 | : begin(range.getBegin(), sourceManager), end(range.getEnd(), sourceManager) {
39 | }
40 |
41 | Range::Range(Offset begin_, Offset end_) : begin(begin_), end(end_) {
42 | }
43 |
44 | nlohmann::json Range::toJson() const {
45 | // clang-format off
46 | return {
47 | {"begin", begin.toJson()},
48 | {"end", end.toJson()}
49 | };
50 | // clang-format on
51 | }
52 |
53 | } // namespace ClangExpand
54 |
--------------------------------------------------------------------------------
/source/common/routines.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/common/routines.hpp"
27 | #include "clang-expand/common/canonical-location.hpp"
28 |
29 | // Clang includes
30 | #include
31 | #include
32 | #include
33 |
34 | // LLVM includes
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 |
42 | // Standard includes
43 | #include
44 | #include
45 | #include
46 | #include
47 |
48 | namespace ClangExpand {
49 | namespace Routines {
50 | bool locationsAreEqual(const clang::SourceLocation& first,
51 | const clang::SourceLocation& second,
52 | const clang::SourceManager& sourceManager) {
53 | return CanonicalLocation(first, sourceManager) ==
54 | CanonicalLocation(second, sourceManager);
55 | }
56 |
57 | std::string getSourceText(const clang::SourceRange& range,
58 | clang::SourceManager& sourceManager,
59 | const clang::LangOptions& languageOptions) {
60 | clang::Rewriter rewriter(sourceManager, languageOptions);
61 | return rewriter.getRewrittenText(range);
62 | }
63 |
64 | std::string getSourceText(const clang::SourceRange& range,
65 | clang::ASTContext& context) {
66 | return getSourceText(range,
67 | context.getSourceManager(),
68 | context.getLangOpts());
69 | }
70 |
71 | std::string makeAbsolute(const std::string& filename) {
72 | llvm::SmallString<256> absolutePath(filename);
73 | const auto failure = llvm::sys::path::remove_dots(absolutePath, true);
74 | assert(!failure && "Error cleaning path before making it absolute");
75 | (void)failure;
76 | const auto error = llvm::sys::fs::make_absolute(absolutePath);
77 | assert(!error && "Error generating absolute path");
78 | (void)error;
79 | return absolutePath.str();
80 | }
81 |
82 | void error(const char* message) {
83 | llvm::errs() << message << '\n';
84 | std::exit(EXIT_FAILURE);
85 | }
86 |
87 | void error(llvm::Twine&& twine) {
88 | llvm::errs() << twine.str() << '\n';
89 | std::exit(EXIT_FAILURE);
90 | }
91 |
92 | } // namespace Routines
93 | } // namespace ClangExpand
94 |
--------------------------------------------------------------------------------
/source/definition-search/action.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/definition-search/action.hpp"
27 | #include "clang-expand/common/routines.hpp"
28 | #include "clang-expand/definition-search/consumer.hpp"
29 |
30 | // LLVM includes
31 | #include
32 |
33 | // Standard includes
34 | #include
35 |
36 | namespace ClangExpand {
37 | namespace DefinitionSearch {
38 | Action::Action(const std::string& declarationFile, Query& query)
39 | : _declarationFile(Routines::makeAbsolute(declarationFile)), _query(query) {
40 | }
41 |
42 | Action::ASTConsumerPointer Action::CreateASTConsumer(clang::CompilerInstance&,
43 | llvm::StringRef filename) {
44 | // Skip the file we found the declaration in
45 | if (filename == _declarationFile) return nullptr;
46 | return std::make_unique(_query);
47 | }
48 |
49 | } // namespace DefinitionSearch
50 | } // namespace ClangExpand
51 |
--------------------------------------------------------------------------------
/source/definition-search/consumer.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/definition-search/consumer.hpp"
27 | #include "clang-expand/common/declaration-data.hpp"
28 | #include "clang-expand/common/query.hpp"
29 |
30 | // Clang includes
31 | #include
32 | #include
33 | #include
34 |
35 | // LLVM includes
36 | #include
37 |
38 | namespace ClangExpand {
39 | namespace DefinitionSearch {
40 | namespace {
41 |
42 | /// Creates an ASTMatcher expression matching on functions that have a
43 | /// definition and the same name as the function whose declaration we serialized
44 | /// into the `DeclarationData` object.
45 | auto createAstMatcher(const DeclarationData& declaration) {
46 | using namespace clang::ast_matchers; // NOLINT(build/namespaces)
47 | return functionDecl(isDefinition(), hasName(declaration.name)).bind("fn");
48 | }
49 | } // namespace
50 |
51 | Consumer::Consumer(Query& query) : _query(query), _matchHandler(query) {
52 | }
53 |
54 | void Consumer::HandleTranslationUnit(clang::ASTContext& context) {
55 | const auto matcher = createAstMatcher(*_query.declaration);
56 | clang::ast_matchers::MatchFinder matchFinder;
57 | matchFinder.addMatcher(matcher, &_matchHandler);
58 | matchFinder.matchAST(context);
59 | }
60 | } // namespace DefinitionSearch
61 | } // namespace ClangExpand
62 |
--------------------------------------------------------------------------------
/source/definition-search/match-handler.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/definition-search/match-handler.hpp"
27 | #include "clang-expand/common/context-data.hpp"
28 | #include "clang-expand/common/declaration-data.hpp"
29 | #include "clang-expand/common/definition-data.hpp"
30 | #include "clang-expand/common/query.hpp"
31 |
32 | // Clang includes
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 |
39 | // LLVM includes
40 | #include
41 | #include
42 | #include
43 | #include
44 |
45 | // Standard includes
46 | #include
47 | #include
48 | #include
49 |
50 | namespace ClangExpand {
51 | namespace DefinitionSearch {
52 | namespace {
53 | /// Compares a kind of `Context` with an expected `ContextData`. Their kind
54 | /// (namespace, class etc.) and name must match.
55 | template
56 | bool contextMatches(const Context& context,
57 | const ContextData& expectedContext) {
58 | if (context.getDeclKind() != expectedContext.kind) return false;
59 | if (context.getName() != expectedContext.name) return false;
60 | return true;
61 | }
62 | } // namespace
63 |
64 | MatchHandler::MatchHandler(Query& query) : _query(query) {
65 | }
66 |
67 | void MatchHandler::run(const MatchResult& result) {
68 | const auto* function = result.Nodes.getNodeAs("fn");
69 | assert(function != nullptr && "Got null function node in match handler");
70 |
71 | const auto& parameterTypes = _query.declaration->parameterTypes;
72 |
73 | if (function->getNumParams() != parameterTypes.size()) return;
74 |
75 | if (!_matchParameters(*result.Context, *function)) return;
76 | if (!_matchContexts(*function)) return;
77 |
78 | auto definition = DefinitionData::Collect(*function, *result.Context, _query);
79 | _query.definition = std::move(definition);
80 | }
81 |
82 | bool MatchHandler::_matchParameters(const clang::ASTContext& context,
83 | const clang::FunctionDecl& function) const
84 | noexcept {
85 | const auto& policy = context.getPrintingPolicy();
86 |
87 | auto expectedType = _query.declaration->parameterTypes.begin();
88 | for (const auto* parameter : function.parameters()) {
89 | const auto type = parameter->getOriginalType().getCanonicalType();
90 | if (*expectedType != type.getAsString(policy)) return false;
91 | ++expectedType;
92 | }
93 |
94 | return true;
95 | }
96 |
97 | bool MatchHandler::_matchContexts(const clang::FunctionDecl& function) const
98 | noexcept {
99 | auto expectedContext = _query.declaration->contexts.begin();
100 |
101 | const auto* context = function.getPrimaryContext()->getParent();
102 | for (; context; context = context->getParent()) {
103 | if (auto* ns = llvm::dyn_cast(context)) {
104 | if (!contextMatches(*ns, *expectedContext)) return false;
105 | ++expectedContext;
106 | } else if (auto* record = llvm::dyn_cast(context)) {
107 | if (!contextMatches(*record, *expectedContext)) return false;
108 | ++expectedContext;
109 | }
110 | }
111 |
112 | return true;
113 | }
114 |
115 | } // namespace DefinitionSearch
116 | } // namespace ClangExpand
117 |
--------------------------------------------------------------------------------
/source/definition-search/tool-factory.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/definition-search/tool-factory.hpp"
27 | #include "clang-expand/common/query.hpp"
28 | #include "clang-expand/definition-search/action.hpp"
29 |
30 | // Clang includes
31 | #include
32 |
33 | // Standard includes
34 | #include
35 |
36 | namespace ClangExpand {
37 | namespace DefinitionSearch {
38 | ToolFactory::ToolFactory(const std::string& declarationFile, Query& query)
39 | : _declarationFile(declarationFile), _query(query) {
40 | }
41 |
42 | clang::FrontendAction* ToolFactory::create() {
43 | return new DefinitionSearch::Action(_declarationFile, _query);
44 | }
45 |
46 | } // namespace DefinitionSearch
47 | } // namespace ClangExpand
48 |
--------------------------------------------------------------------------------
/source/result.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/result.hpp"
27 | #include "clang-expand/common/call-data.hpp"
28 | #include "clang-expand/common/definition-data.hpp"
29 | #include "clang-expand/common/query.hpp"
30 | #include "clang-expand/options.hpp"
31 |
32 | // Third party includes
33 | #include
34 |
35 | // LLVM includes
36 | #include
37 |
38 | // Standard includes
39 | #include
40 | #include
41 |
42 | namespace ClangExpand {
43 | Result::Result(Query&& query) {
44 | if (query.options.wantsCall) {
45 | assert(query.call.hasValue() &&
46 | "User wants call information, but have no call data.");
47 | callRange = query.call->extent;
48 | }
49 | if (query.options.wantsDeclaration) {
50 | declaration = std::move(query.declaration);
51 | }
52 | if (query.requiresDefinition()) {
53 | definition = std::move(query.definition);
54 | }
55 | }
56 |
57 | nlohmann::json Result::toJson() const {
58 | nlohmann::json json;
59 |
60 | if (callRange.hasValue()) {
61 | json["call"] = callRange->toJson();
62 | }
63 |
64 | if (declaration.hasValue()) {
65 | json["declaration"] = declaration->toJson();
66 | }
67 |
68 | if (definition.hasValue()) {
69 | json["definition"] = definition->toJson();
70 | }
71 |
72 | return json.is_null() ? "" : json;
73 | }
74 |
75 | } // namespace ClangExpand
76 |
--------------------------------------------------------------------------------
/source/search.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/search.hpp"
27 | #include "clang-expand/common/query.hpp"
28 | #include "clang-expand/common/routines.hpp"
29 | #include "clang-expand/definition-search/tool-factory.hpp"
30 | #include "clang-expand/result.hpp"
31 | #include "clang-expand/symbol-search/tool-factory.hpp"
32 |
33 | // Clang includes
34 | #include
35 |
36 | // LLVM includes
37 | #include
38 | #include
39 | #include
40 |
41 | // Standard includes
42 | #include
43 | #include
44 | #include
45 |
46 | namespace ClangExpand {
47 | Search::Search(const std::string& file, unsigned line, unsigned column)
48 | : _location(Routines::makeAbsolute(file), line, column) {
49 | }
50 |
51 | Result Search::run(clang::tooling::CompilationDatabase& compilationDatabase,
52 | const SourceVector& sources,
53 | const Options& options) {
54 | Query query(options);
55 |
56 | _symbolSearch(compilationDatabase, query);
57 |
58 | if (query.foundNothing()) {
59 | Routines::error("Could not recognize token at specified location");
60 | }
61 |
62 | if (query.requiresDefinition()) {
63 | if (!query.definition) {
64 | _definitionSearch(compilationDatabase, sources, query);
65 | }
66 |
67 | if (!query.definition) {
68 | Routines::error("Could not find definition");
69 | }
70 | }
71 |
72 | return Result(std::move(query));
73 | }
74 |
75 | void Search::_symbolSearch(CompilationDatabase& compilationDatabase,
76 | Query& query) {
77 | clang::tooling::ClangTool SymbolSearch(compilationDatabase,
78 | {_location.filename});
79 |
80 | const auto error = SymbolSearch.run(
81 | new ClangExpand::SymbolSearch::ToolFactory(_location, query));
82 | if (error) std::exit(error);
83 | }
84 |
85 | void Search::_definitionSearch(CompilationDatabase& compilationDatabase,
86 | const SourceVector& sources,
87 | Query& query) {
88 | clang::tooling::ClangTool DefinitionSearch(compilationDatabase, sources);
89 |
90 | const auto error = DefinitionSearch.run(
91 | new ClangExpand::DefinitionSearch::ToolFactory(_location.filename,
92 | query));
93 | if (error) std::exit(error);
94 | }
95 |
96 | } // namespace ClangExpand
97 |
--------------------------------------------------------------------------------
/source/symbol-search/action.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/symbol-search/action.hpp"
27 | #include "clang-expand/common/offset.hpp"
28 | #include "clang-expand/common/query.hpp"
29 | #include "clang-expand/common/routines.hpp"
30 | #include "clang-expand/symbol-search/consumer.hpp"
31 | #include "clang-expand/symbol-search/macro-search.hpp"
32 |
33 | // Clang includes
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 |
43 | // LLVM includes
44 | #include
45 | #include
46 | #include
47 |
48 | // Standard includes
49 | #include
50 | #include
51 | #include
52 | #include
53 |
54 |
55 | namespace ClangExpand {
56 | namespace SymbolSearch {
57 | namespace {
58 |
59 | /// Makes sure the token under the cursor is something we can handle.
60 | ///
61 | /// "Things we can handle" means either (1) identifiers (for functions, macros,
62 | /// methods etc.) or (2) operators (for overloads).
63 | ///
64 | /// \returns True if the token is an operator, else false if it is a simple
65 | /// identifier.
66 | bool verifyToken(const clang::Token& token) {
67 | static const llvm::StringSet<> operatorTokens = {
68 | "amp", // &
69 | "ampamp", // &&
70 | "ampequal", // &=
71 | "star", // *
72 | "starequal", // *=
73 | "plus", // +
74 | "plusequal", // +=
75 | "minus", // -
76 | "minusminus", // --
77 | "minusequal", // -=
78 | "tilde", // ~
79 | "exclaim", // !
80 | "exclaimequal", // !=
81 | "slash", // /
82 | "slashequal", // /=
83 | "percent", // %
84 | "percentequal", // %=
85 | "less", // <
86 | "lessless", // <<
87 | "lessequal", // <=
88 | "lesslessequal", // <<=
89 | "greater", // >
90 | "greatergreater", // >>
91 | "greaterequal", // >=
92 | "greatergreaterequal", // >>=
93 | "caret", // ^
94 | "caretequal", // ^=
95 | "pipe", // |
96 | "pipepipe", // ||
97 | "pipeequal", // |=
98 | "equalequal" // ==
99 | };
100 |
101 | if (token.is(clang::tok::raw_identifier)) return false;
102 | if (operatorTokens.count(token.getName())) return true;
103 |
104 | Routines::error("Token at given location is not an identifier");
105 | }
106 |
107 | /// Attempts to get the `clang::FileID` for the target location.
108 | clang::FileID getFileID(const Location& targetLocation,
109 | clang::SourceManager& sourceManager) {
110 | auto& fileManager = sourceManager.getFileManager();
111 | const auto* fileEntry = fileManager.getFile(targetLocation.filename);
112 | if (fileEntry == nullptr || !fileEntry->isValid()) {
113 | Routines::error("Could not find file " +
114 | llvm::Twine(targetLocation.filename) +
115 | " in file manager\n");
116 | }
117 |
118 | assert(fileEntry->getName() == targetLocation.filename &&
119 | "Symbol search should only run on the target TU");
120 |
121 | const auto fileID =
122 | sourceManager.getOrCreateFileID(fileEntry, clang::SrcMgr::C_User);
123 | if (!fileID.isValid()) {
124 | Routines::error("Error getting file ID from file entry");
125 | }
126 |
127 | return fileID;
128 | }
129 |
130 | /// Translates our friendly representation of a location to a compact
131 | /// `clang::SourceLocation` for further processing with clang APIs.
132 | clang::SourceLocation translateLocation(const Location& location,
133 | clang::SourceManager& sourceManager) {
134 | const auto fileID = getFileID(location, sourceManager);
135 | const auto line = location.offset.line;
136 | const auto column = location.offset.column;
137 | const auto translated = sourceManager.translateLineCol(fileID, line, column);
138 | if (translated.isInvalid()) {
139 | Routines::error("Location is not valid");
140 | }
141 | return translated;
142 | }
143 |
144 | /// Given a location between the start and end of a token, returns a location
145 | /// for the start of the token.
146 | clang::SourceLocation
147 | getBeginningOfToken(const clang::SourceLocation& somewhere,
148 | clang::SourceManager& sourceManager,
149 | const clang::LangOptions& languageOptions) {
150 | const auto startLocation = clang::Lexer::GetBeginningOfToken(somewhere,
151 | sourceManager,
152 | languageOptions);
153 |
154 | if (startLocation.isInvalid()) {
155 | Routines::error("Error retrieving start of token");
156 | }
157 |
158 | return startLocation;
159 | }
160 |
161 | /// Lexes the token at the given location.
162 | clang::Token lex(const clang::SourceLocation& startLocation,
163 | clang::SourceManager& sourceManager,
164 | const clang::LangOptions& languageOptions) {
165 | clang::Token token;
166 | bool errorOccurred = clang::Lexer::getRawToken(startLocation,
167 | token,
168 | sourceManager,
169 | languageOptions,
170 | /*IgnoreWhiteSpace=*/true);
171 | if (errorOccurred) {
172 | Routines::error("Error lexing token at given location");
173 | }
174 |
175 | return token;
176 | }
177 | } // namespace
178 |
179 | Action::Action(Location targetLocation, Query& query)
180 | : _query(query), _targetLocation(std::move(targetLocation)) {
181 | }
182 |
183 | bool Action::BeginSourceFileAction(clang::CompilerInstance& compiler,
184 | llvm::StringRef filename) {
185 | if (!super::BeginSourceFileAction(compiler, filename)) return false;
186 |
187 | auto& sourceManager = compiler.getSourceManager();
188 | const clang::SourceLocation location =
189 | translateLocation(_targetLocation, sourceManager);
190 |
191 | const auto& languageOptions = compiler.getLangOpts();
192 | const auto& startLocation =
193 | getBeginningOfToken(location, sourceManager, languageOptions);
194 |
195 | clang::Token token = lex(startLocation, sourceManager, languageOptions);
196 | bool isOperator = verifyToken(token);
197 |
198 | // Good to go.
199 | _callLocation = startLocation;
200 | _spelling = clang::Lexer::getSpelling(token, sourceManager, languageOptions);
201 |
202 | if (isOperator) _spelling = "operator" + _spelling;
203 |
204 | _installMacroFacilities(compiler);
205 |
206 | /// Continue.
207 | return true;
208 | }
209 |
210 | Action::ASTConsumerPointer Action::CreateASTConsumer(clang::CompilerInstance&,
211 | llvm::StringRef) {
212 | return std::make_unique(_callLocation, _spelling, _query);
213 | }
214 |
215 | void Action::_installMacroFacilities(clang::CompilerInstance& compiler) const {
216 | auto hooks = std::make_unique(compiler, _callLocation, _query);
217 | compiler.getPreprocessor().addPPCallbacks(std::move(hooks));
218 | }
219 |
220 | } // namespace SymbolSearch
221 | } // namespace ClangExpand
222 |
--------------------------------------------------------------------------------
/source/symbol-search/consumer.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/symbol-search/consumer.hpp"
27 |
28 | // Clang includes
29 | #include
30 | #include
31 | #include
32 |
33 | // Standard includes
34 | #include
35 |
36 | namespace ClangExpand {
37 | namespace SymbolSearch {
38 | namespace {
39 | /// Creates an ASTMatcher matching function or method call expressions as well
40 | /// as constructor invocations.
41 | auto createAstMatcher(const std::string& spelling) {
42 | using namespace clang::ast_matchers; // NOLINT(build/namespaces)
43 | // clang-format off
44 | return expr(anyOf(
45 | callExpr(anyOf(
46 | hasDescendant(declRefExpr(
47 | hasDeclaration(functionDecl(hasName(spelling)).bind("fn")))
48 | .bind("ref")),
49 | hasDescendant(memberExpr(
50 | hasDeclaration(cxxMethodDecl(hasName(spelling)).bind("fn")))
51 | .bind("member"))))
52 | .bind("call"),
53 | cxxConstructExpr(
54 | hasDeclaration(
55 | cxxConstructorDecl(
56 | hasName(spelling),
57 | isUserProvided())
58 | .bind("fn")))
59 | .bind("construct")));
60 | // clang-format on
61 | }
62 | } // namespace
63 |
64 | Consumer::Consumer(const clang::SourceLocation& invocationLocation,
65 | std::string callSpelling,
66 | Query& query)
67 | : _callSpelling(std::move(callSpelling))
68 | , _matchHandler(invocationLocation, query) {
69 | }
70 |
71 | void Consumer::HandleTranslationUnit(clang::ASTContext& context) {
72 | const auto matcher = createAstMatcher(_callSpelling);
73 | clang::ast_matchers::MatchFinder matchFinder;
74 | matchFinder.addMatcher(matcher, &_matchHandler);
75 | matchFinder.matchAST(context);
76 | }
77 |
78 | } // namespace SymbolSearch
79 | } // namespace ClangExpand
80 |
--------------------------------------------------------------------------------
/source/symbol-search/macro-search.cpp:
--------------------------------------------------------------------------------
1 | //===----------------------------------------------------------------------===//
2 | //
3 | // The MIT License (MIT)
4 | // Copyright (c) 2017 Peter Goldsborough
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 | //===----------------------------------------------------------------------===//
24 |
25 | // Project includes
26 | #include "clang-expand/symbol-search/macro-search.hpp"
27 | #include "clang-expand/common/call-data.hpp"
28 | #include "clang-expand/common/definition-data.hpp"
29 | #include "clang-expand/common/location.hpp"
30 | #include "clang-expand/common/query.hpp"
31 | #include "clang-expand/common/range.hpp"
32 | #include "clang-expand/common/routines.hpp"
33 |
34 | // Clang includes
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 |
46 | // LLVM includes
47 | #include