20 filename = os.path.join(module_path,
'CMakeLists.txt')
21 with open(filename,
'r') as f: 24 cpp_file = check_name_camel + '.cpp' 28 if line.strip() == cpp_file:
31 print(
'Updating %s...' % filename)
32 with open(filename,
'wb')
as f:
36 cpp_line = line.strip().endswith(
'.cpp')
37 if (
not file_added)
and (cpp_line
or cpp_found):
39 if (line.strip() > cpp_file)
or (
not cpp_line):
40 f.write(
' ' + cpp_file +
'\n')
48 def write_header(module_path, module, check_name, check_name_camel):
49 check_name_dashes = module +
'-' + check_name
50 filename = os.path.join(module_path, check_name_camel) +
'.h' 51 print(
'Creating %s...' % filename)
52 with open(filename,
'wb')
as f:
53 header_guard = (
'LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_' + module.upper() +
'_' 54 + check_name_camel.upper() +
'_H')
56 f.write(os.path.basename(filename))
57 f.write(
' - clang-tidy')
58 f.write(
'-' * max(0, 43 - len(os.path.basename(filename))))
59 f.write(
'*- C++ -*-===//')
62 // The LLVM Compiler Infrastructure 64 // This file is distributed under the University of Illinois Open Source 65 // License. See LICENSE.TXT for details. 67 //===----------------------------------------------------------------------===// 69 #ifndef %(header_guard)s 70 #define %(header_guard)s 72 #include "../ClangTidy.h" 76 namespace %(module)s { 78 /// FIXME: Write a short description. 80 /// For the user-facing documentation see: 81 /// http://clang.llvm.org/extra/clang-tidy/checks/%(check_name_dashes)s.html 82 class %(check_name)s : public ClangTidyCheck { 84 %(check_name)s(StringRef Name, ClangTidyContext *Context) 85 : ClangTidyCheck(Name, Context) {} 86 void registerMatchers(ast_matchers::MatchFinder *Finder) override; 87 void check(const ast_matchers::MatchFinder::MatchResult &Result) override; 90 } // namespace %(module)s 94 #endif // %(header_guard)s 95 """ % {
'header_guard': header_guard,
96 'check_name': check_name_camel,
97 'check_name_dashes': check_name_dashes,
103 filename = os.path.join(module_path, check_name_camel) +
'.cpp' 104 print(
'Creating %s...' % filename)
105 with open(filename,
'wb')
as f:
107 f.write(os.path.basename(filename))
108 f.write(
' - clang-tidy')
109 f.write(
'-' * max(0, 52 - len(os.path.basename(filename))))
113 // The LLVM Compiler Infrastructure 115 // This file is distributed under the University of Illinois Open Source 116 // License. See LICENSE.TXT for details. 118 //===----------------------------------------------------------------------===// 120 #include "%(check_name)s.h" 121 #include "clang/AST/ASTContext.h" 122 #include "clang/ASTMatchers/ASTMatchFinder.h" 124 using namespace clang::ast_matchers; 128 namespace %(module)s { 130 void %(check_name)s::registerMatchers(MatchFinder *Finder) { 131 // FIXME: Add matchers. 132 Finder->addMatcher(functionDecl().bind("x"), this); 135 void %(check_name)s::check(const MatchFinder::MatchResult &Result) { 136 // FIXME: Add callback implementation. 137 const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>("x"); 138 if (MatchedDecl->getName().startswith("awesome_")) 140 diag(MatchedDecl->getLocation(), "function %%0 is insufficiently awesome") 142 << FixItHint::CreateInsertion(MatchedDecl->getLocation(), "awesome_"); 145 } // namespace %(module)s 148 """ % {
'check_name': check_name_camel,
154 modulecpp = filter(
lambda p: p.lower() == module.lower() +
'tidymodule.cpp',
155 os.listdir(module_path))[0]
156 filename = os.path.join(module_path, modulecpp)
157 with open(filename,
'r') as f: 158 lines = f.readlines() 160 print('Updating %s...' % filename)
161 with open(filename,
'wb')
as f:
165 check_decl = (
' CheckFactories.registerCheck<' + check_name_camel +
166 '>(\n "' + module +
'-' + check_name +
'");\n')
170 match = re.search(
'#include "(.*)"', line)
173 if match.group(1) > check_name_camel:
175 f.write(
'#include "' + check_name_camel +
'.h"\n')
178 f.write(
'#include "' + check_name_camel +
'.h"\n')
181 if line.strip() ==
'}':
185 match = re.search(
'registerCheck<(.*)>', line)
186 if match
and match.group(1) > check_name_camel:
194 check_name_dashes = module +
'-' + check_name
195 filename = os.path.normpath(os.path.join(module_path,
196 '../../docs/ReleaseNotes.rst'))
197 with open(filename,
'r') as f: 198 lines = f.readlines() 200 print('Updating %s...' % filename)
201 with open(filename,
'wb')
as f:
207 match = re.search(
'Improvements to clang-tidy', line)
211 if not line.startswith(
'----'):
214 <http://clang.llvm.org/extra/clang-tidy/checks/%s.html>`_ check 216 FIXME: add release notes. 217 """ % (check_name_dashes, check_name_dashes))
225 check_name_dashes = module +
'-' + check_name
226 filename = os.path.normpath(os.path.join(module_path,
'../../test/clang-tidy',
227 check_name_dashes +
'.cpp'))
228 print(
'Creating %s...' % filename)
229 with open(filename,
'wb')
as f:
230 f.write(
"""// RUN: %%check_clang_tidy %%s %(check_name_dashes)s %%t 232 // FIXME: Add something that triggers the check here. 234 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [%(check_name_dashes)s] 236 // FIXME: Verify the applied fix. 237 // * Make the CHECK patterns specific enough and try to make verified lines 238 // unique to avoid incorrect matches. 239 // * Use {{}} for regular expressions. 240 // CHECK-FIXES: {{^}}void awesome_f();{{$}} 242 // FIXME: Add something that doesn't trigger the check here. 244 """ % {
'check_name_dashes': check_name_dashes})
249 docs_dir = os.path.join(clang_tidy_path,
'../docs/clang-tidy/checks')
250 filename = os.path.normpath(os.path.join(docs_dir,
'list.rst'))
251 with open(filename,
'r') as f: 252 lines = f.readlines() 253 doc_files = filter(lambda s: s.endswith(
'.rst')
and s !=
'list.rst',
254 os.listdir(docs_dir))
257 def format_link(doc_file):
258 check_name = doc_file.replace(
'.rst',
'')
259 with open(os.path.join(docs_dir, doc_file),
'r') as doc: 261 match = re.search('.*:orphan:.*', content)
265 match = re.search(
'.*:http-equiv=refresh: \d+;URL=(.*).html.*',
268 return ' %(check)s (redirects to %(target)s) <%(check)s>\n' % {
270 'target': match.group(1)
272 return ' %s\n' % check_name
274 checks = map(format_link, doc_files)
276 print(
'Updating %s...' % filename)
277 with open(filename,
'wb')
as f:
280 if line.startswith(
'.. toctree::'):
287 check_name_dashes = module +
'-' + check_name
288 filename = os.path.normpath(os.path.join(
289 module_path,
'../../docs/clang-tidy/checks/', check_name_dashes +
'.rst'))
290 print(
'Creating %s...' % filename)
291 with open(filename,
'wb')
as f:
292 f.write(
""".. title:: clang-tidy - %(check_name_dashes)s 294 %(check_name_dashes)s 297 FIXME: Describe what patterns does the check detect and why. Give examples. 298 """ % {
'check_name_dashes': check_name_dashes,
299 'underline':
'=' * len(check_name_dashes)})
303 if len(sys.argv) == 2
and sys.argv[1] ==
'--update-docs':
307 if len(sys.argv) != 3:
309 Usage: add_new_check.py <module> <check>, e.g. 310 add_new_check.py misc awesome-functions 312 Alternatively, run 'add_new_check.py --update-docs' to just update the list of 313 documentation files.""" 318 check_name = sys.argv[2]
320 if check_name.startswith(module):
321 print 'Check name "%s" must not start with the module "%s". Exiting.' % (
324 check_name_camel =
''.
join(map(
lambda elem: elem.capitalize(),
325 check_name.split(
'-'))) +
'Check' 326 clang_tidy_path = os.path.dirname(sys.argv[0])
327 module_path = os.path.join(clang_tidy_path, module)
331 write_header(module_path, module, check_name, check_name_camel)
333 adapt_module(module_path, module, check_name, check_name_camel)
338 print(
'Done. Now it\'s your turn!')
341 if __name__ ==
'__main__':
def write_header(module_path, module, check_name, check_name_camel)
def write_docs(module_path, module, check_name)
def write_test(module_path, module, check_name)
def add_release_notes(module_path, module, check_name)
def write_implementation(module_path, module, check_name_camel)
def update_checks_list(clang_tidy_path)
def adapt_module(module_path, module, check_name, check_name_camel)
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
def adapt_cmake(module_path, check_name_camel)