1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef SANDBOXED_API_TOOLS_CLANG_GENERATOR_GENERATOR_H_
16 #define SANDBOXED_API_TOOLS_CLANG_GENERATOR_GENERATOR_H_
17
18 #include <memory>
19 #include <string>
20 #include <utility>
21 #include <vector>
22
23 #include "absl/container/flat_hash_set.h"
24 #include "absl/strings/string_view.h"
25 #include "clang/AST/ASTConsumer.h"
26 #include "clang/AST/Decl.h"
27 #include "clang/AST/RecursiveASTVisitor.h"
28 #include "clang/Frontend/CompilerInstance.h"
29 #include "clang/Frontend/CompilerInvocation.h"
30 #include "clang/Frontend/FrontendAction.h"
31 #include "clang/Lex/Preprocessor.h"
32 #include "clang/Tooling/Tooling.h"
33 #include "sandboxed_api/tools/clang_generator/emitter.h"
34 #include "sandboxed_api/tools/clang_generator/types.h"
35
36 namespace sapi {
37
38 struct GeneratorOptions {
39 template <typename ContainerT>
set_function_namesGeneratorOptions40 GeneratorOptions& set_function_names(const ContainerT& value) {
41 function_names.clear();
42 function_names.insert(std::begin(value), std::end(value));
43 return *this;
44 }
45
46 template <typename ContainerT>
set_in_filesGeneratorOptions47 GeneratorOptions& set_in_files(const ContainerT& value) {
48 in_files.clear();
49 in_files.insert(std::begin(value), std::end(value));
50 return *this;
51 }
52
set_limit_scan_depthGeneratorOptions53 GeneratorOptions& set_limit_scan_depth(bool value) {
54 limit_scan_depth = value;
55 return *this;
56 }
57
has_namespaceGeneratorOptions58 bool has_namespace() const { return !namespace_name.empty(); }
59
60 absl::flat_hash_set<std::string> function_names;
61 absl::flat_hash_set<std::string> in_files;
62 bool limit_scan_depth = false;
63
64 // Output options
65 std::string work_dir;
66 std::string name; // Name of the Sandboxed API
67 std::string namespace_name; // Namespace to wrap the SAPI in
68 // Output path of the generated header. Used to build the header include
69 // guard.
70 std::string out_file = "out_file.cc";
71 std::string embed_dir; // Directory with embedded includes
72 std::string embed_name; // Identifier of the embed object
73 };
74
75 class GeneratorASTVisitor
76 : public clang::RecursiveASTVisitor<GeneratorASTVisitor> {
77 public:
GeneratorASTVisitor(const GeneratorOptions & options)78 explicit GeneratorASTVisitor(const GeneratorOptions& options)
79 : options_(options) {}
80
81 bool VisitTypeDecl(clang::TypeDecl* decl);
82 bool VisitFunctionDecl(clang::FunctionDecl* decl);
83
collector()84 TypeCollector& collector() { return collector_; }
85
functions()86 const std::vector<clang::FunctionDecl*>& functions() const {
87 return functions_;
88 }
89
90 private:
91 TypeCollector collector_;
92 std::vector<clang::FunctionDecl*> functions_;
93 const GeneratorOptions& options_;
94 };
95
96 class GeneratorASTConsumer : public clang::ASTConsumer {
97 public:
GeneratorASTConsumer(std::string in_file,Emitter & emitter,const GeneratorOptions & options)98 GeneratorASTConsumer(std::string in_file, Emitter& emitter,
99 const GeneratorOptions& options)
100 : in_file_(std::move(in_file)), visitor_(options), emitter_(emitter) {}
101
102 private:
103 void HandleTranslationUnit(clang::ASTContext& context) override;
104
105 std::string in_file_;
106 GeneratorASTVisitor visitor_;
107 Emitter& emitter_;
108 };
109
110 class GeneratorAction : public clang::ASTFrontendAction {
111 public:
GeneratorAction(Emitter & emitter,const GeneratorOptions & options)112 GeneratorAction(Emitter& emitter, const GeneratorOptions& options)
113 : emitter_(emitter), options_(options) {}
114
115 private:
CreateASTConsumer(clang::CompilerInstance &,llvm::StringRef in_file)116 std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
117 clang::CompilerInstance&, llvm::StringRef in_file) override {
118 return std::make_unique<GeneratorASTConsumer>(std::string(in_file),
119 emitter_, options_);
120 }
121
BeginSourceFileAction(clang::CompilerInstance & ci)122 bool BeginSourceFileAction(clang::CompilerInstance& ci) override {
123 ci.getPreprocessor().enableIncrementalProcessing();
124 return true;
125 }
126
hasCodeCompletionSupport()127 bool hasCodeCompletionSupport() const override { return false; }
128
129 Emitter& emitter_;
130 const GeneratorOptions& options_;
131 };
132
133 class GeneratorFactory : public clang::tooling::FrontendActionFactory {
134 public:
135 // Does not take ownership
GeneratorFactory(Emitter & emitter,const GeneratorOptions & options)136 GeneratorFactory(Emitter& emitter, const GeneratorOptions& options)
137 : emitter_(emitter), options_(options) {}
138
139 private:
140 #if LLVM_VERSION_MAJOR >= 10
create()141 std::unique_ptr<clang::FrontendAction> create() override {
142 return std::make_unique<GeneratorAction>(emitter_, options_);
143 }
144 #else
145 clang::FrontendAction* create() override {
146 return new GeneratorAction(emitter_, options_);
147 }
148 #endif
149
150 bool runInvocation(
151 std::shared_ptr<clang::CompilerInvocation> invocation,
152 clang::FileManager* files,
153 std::shared_ptr<clang::PCHContainerOperations> pch_container_ops,
154 clang::DiagnosticConsumer* diag_consumer) override;
155
156 Emitter& emitter_;
157 const GeneratorOptions& options_;
158 };
159
160 std::string GetOutputFilename(absl::string_view source_file);
161
ToStringView(llvm::StringRef ref)162 inline absl::string_view ToStringView(llvm::StringRef ref) {
163 return absl::string_view(ref.data(), ref.size());
164 }
165
166 } // namespace sapi
167
168 #endif // SANDBOXED_API_TOOLS_CLANG_GENERATOR_GENERATOR_H_
169