xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/tools/clang_generator/generator.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
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 #include "sandboxed_api/tools/clang_generator/generator.h"
16 
17 #include <memory>
18 #include <optional>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 
23 #include "absl/container/flat_hash_set.h"
24 #include "absl/status/status.h"
25 #include "absl/strings/match.h"
26 #include "absl/strings/str_cat.h"
27 #include "absl/strings/string_view.h"
28 #include "absl/strings/strip.h"
29 #include "clang/AST/ASTContext.h"
30 #include "clang/AST/Decl.h"
31 #include "clang/AST/Type.h"
32 #include "clang/Basic/SourceLocation.h"
33 #include "clang/Basic/SourceManager.h"
34 #include "clang/Lex/PreprocessorOptions.h"
35 #include "sandboxed_api/tools/clang_generator/diagnostics.h"
36 #include "sandboxed_api/tools/clang_generator/emitter.h"
37 
38 namespace sapi {
39 namespace {
40 
41 // Replaces the file extension of a path name.
ReplaceFileExtension(absl::string_view path,absl::string_view new_extension)42 std::string ReplaceFileExtension(absl::string_view path,
43                                  absl::string_view new_extension) {
44   auto last_slash = path.rfind('/');
45   auto pos = path.rfind('.', last_slash);
46   if (pos != absl::string_view::npos && last_slash != absl::string_view::npos) {
47     pos += last_slash;
48   }
49   return absl::StrCat(path.substr(0, pos), new_extension);
50 }
51 
52 }  // namespace
53 
GetOutputFilename(absl::string_view source_file)54 std::string GetOutputFilename(absl::string_view source_file) {
55   return ReplaceFileExtension(source_file, ".sapi.h");
56 }
57 
VisitTypeDecl(clang::TypeDecl * decl)58 bool GeneratorASTVisitor::VisitTypeDecl(clang::TypeDecl* decl) {
59   collector_.RecordOrderedDecl(decl);
60   return true;
61 }
62 
VisitFunctionDecl(clang::FunctionDecl * decl)63 bool GeneratorASTVisitor::VisitFunctionDecl(clang::FunctionDecl* decl) {
64   if (decl->isCXXClassMember() ||  // Skip classes
65       !decl->isExternC() ||        // Skip non external functions
66       decl->isTemplated()          // Skip function templates
67   ) {
68     return true;
69   }
70 
71   // Process either all function or just the requested ones
72   bool all_functions = options_.function_names.empty();
73   if (!all_functions &&
74       !options_.function_names.contains(ToStringView(decl->getName()))) {
75     return true;
76   }
77 
78   // Skip Abseil internal functions when all functions are requested. This still
79   // allows them to be specified explicitly.
80   if (all_functions &&
81       absl::StartsWith(decl->getQualifiedNameAsString(), "AbslInternal")) {
82     return true;
83   }
84 
85   clang::SourceManager& source_manager =
86       decl->getASTContext().getSourceManager();
87   clang::SourceLocation decl_start = decl->getBeginLoc();
88 
89   // Skip functions from system headers when all functions are requested. Like
90   // above, they can still explicitly be specified.
91   if (all_functions && source_manager.isInSystemHeader(decl_start)) {
92     return true;
93   }
94 
95   if (all_functions) {
96     const std::string filename(absl::StripPrefix(
97         ToStringView(source_manager.getFilename(decl_start)), "./"));
98     if (options_.limit_scan_depth && !options_.in_files.contains(filename)) {
99       return true;
100     }
101   }
102 
103   functions_.push_back(decl);
104 
105   collector_.CollectRelatedTypes(decl->getDeclaredReturnType());
106   for (const clang::ParmVarDecl* param : decl->parameters()) {
107     collector_.CollectRelatedTypes(param->getType());
108   }
109 
110   return true;
111 }
112 
HandleTranslationUnit(clang::ASTContext & context)113 void GeneratorASTConsumer::HandleTranslationUnit(clang::ASTContext& context) {
114   if (!visitor_.TraverseDecl(context.getTranslationUnitDecl())) {
115     ReportFatalError(context.getDiagnostics(),
116                      context.getTranslationUnitDecl()->getBeginLoc(),
117                      "AST traversal exited early");
118     return;
119   }
120 
121   // TODO(cblichmann): Move below to emit all functions after traversing TUs.
122   emitter_.AddTypeDeclarations(visitor_.collector().GetTypeDeclarations());
123   for (clang::FunctionDecl* func : visitor_.functions()) {
124     absl::Status status = emitter_.AddFunction(func);
125     if (!status.ok()) {
126       clang::SourceLocation loc =
127           GetDiagnosticLocationFromStatus(status).value_or(func->getBeginLoc());
128       if (absl::IsCancelled(status)) {
129         ReportWarning(context.getDiagnostics(), loc, status.message());
130         continue;
131       }
132       ReportFatalError(context.getDiagnostics(), loc, status.message());
133       break;
134     }
135   }
136 }
137 
runInvocation(std::shared_ptr<clang::CompilerInvocation> invocation,clang::FileManager * files,std::shared_ptr<clang::PCHContainerOperations> pch_container_ops,clang::DiagnosticConsumer * diag_consumer)138 bool GeneratorFactory::runInvocation(
139     std::shared_ptr<clang::CompilerInvocation> invocation,
140     clang::FileManager* files,
141     std::shared_ptr<clang::PCHContainerOperations> pch_container_ops,
142     clang::DiagnosticConsumer* diag_consumer) {
143   auto& options = invocation->getPreprocessorOpts();
144   // Explicitly ask to define __clang_analyzer__ macro.
145   options.SetUpStaticAnalyzer = true;
146   for (const auto& def : {
147            // Enable code to detect whether it is being SAPI-ized
148            "__SAPI__",
149            // TODO(b/222241644): Figure out how to deal with intrinsics properly
150            // Note: The definitions below just need to parse, they don't need to
151            //       compile into useful code.
152            // Intel
153            "__builtin_ia32_cvtsbf162ss_32=[](auto)->long long{return 0;}",
154            "__builtin_ia32_paddsb128=",
155            "__builtin_ia32_paddsb256=",
156            "__builtin_ia32_paddsb512=",
157            "__builtin_ia32_paddsw128=",
158            "__builtin_ia32_paddsw256=",
159            "__builtin_ia32_paddsw512=",
160            "__builtin_ia32_paddusb128=",
161            "__builtin_ia32_paddusb256=",
162            "__builtin_ia32_paddusb512=",
163            "__builtin_ia32_paddusw128=",
164            "__builtin_ia32_paddusw256=",
165            "__builtin_ia32_paddusw512=",
166            "__builtin_ia32_psubsb128=",
167            "__builtin_ia32_psubsb256=",
168            "__builtin_ia32_psubsb512=",
169            "__builtin_ia32_psubsw128=",
170            "__builtin_ia32_psubsw256=",
171            "__builtin_ia32_psubsw512=",
172            "__builtin_ia32_psubusb128=",
173            "__builtin_ia32_psubusb256=",
174            "__builtin_ia32_psubusb512=",
175            "__builtin_ia32_psubusw128=",
176            "__builtin_ia32_psubusw256=",
177            "__builtin_ia32_psubusw512=",
178            "__builtin_ia32_reduce_add_d512=[](auto)->long long{return 0;}",
179            "__builtin_ia32_reduce_add_q512=[](auto)->long long{return 0;}",
180            "__builtin_ia32_reduce_mul_d512=[](auto)->long long{return 0;}",
181            "__builtin_ia32_reduce_mul_q512=[](auto)->long long{return 0;}",
182        }) {
183     options.addMacroDef(def);
184     // To avoid code to include header with compiler intrinsics, undefine a few
185     // key pre-defines.
186     for (
187         const auto& undef : {
188             // ARM ISA (see
189             // https://developer.arm.com/documentation/101028/0010/Feature-test-macros)
190             "__ARM_NEON",
191             "__ARM_NEON__",
192             // Intel
193             "__AVX__",
194             "__AVX2__",
195             "__AVX512BW__",
196             "__AVX512CD__",
197             "__AVX512DQ__",
198             "__AVX512F__",
199             "__AVX512VL__",
200             "__SSE__",
201             "__SSE2__",
202             "__SSE2_MATH__",
203             "__SSE3__",
204             "__SSE4_1__",
205             "__SSE4_2__",
206             "__SSE_MATH__",
207             "__SSSE3__",
208         }) {
209       options.addMacroUndef(undef);
210     }
211   }
212   return FrontendActionFactory::runInvocation(std::move(invocation), files,
213                                               std::move(pch_container_ops),
214                                               diag_consumer);
215 }
216 
217 }  // namespace sapi
218