xref: /llvm-project/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp (revision 76bbbcb41bcf4a1d7a26bb11b78cf97b60ea7d4b)
1 //===--- HeaderGuardCheck.cpp - clang-tidy --------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "HeaderGuardCheck.h"
10 #include "clang/Tooling/Tooling.h"
11 #include "llvm/Support/Path.h"
12 
13 namespace clang::tidy::llvm_check {
14 
LLVMHeaderGuardCheck(StringRef Name,ClangTidyContext * Context)15 LLVMHeaderGuardCheck::LLVMHeaderGuardCheck(StringRef Name,
16                                            ClangTidyContext *Context)
17     : HeaderGuardCheck(Name, Context) {}
18 
getHeaderGuard(StringRef Filename,StringRef OldGuard)19 std::string LLVMHeaderGuardCheck::getHeaderGuard(StringRef Filename,
20                                                  StringRef OldGuard) {
21   std::string Guard = tooling::getAbsolutePath(Filename);
22 
23   // When running under Windows, need to convert the path separators from
24   // `\` to `/`.
25   Guard = llvm::sys::path::convert_to_slash(Guard);
26 
27   // Sanitize the path. There are some rules for compatibility with the historic
28   // style in include/llvm and include/clang which we want to preserve.
29 
30   // We don't want _INCLUDE_ in our guards.
31   size_t PosInclude = Guard.rfind("include/");
32   if (PosInclude != StringRef::npos)
33     Guard = Guard.substr(PosInclude + std::strlen("include/"));
34 
35   // For clang we drop the _TOOLS_.
36   size_t PosToolsClang = Guard.rfind("tools/clang/");
37   if (PosToolsClang != StringRef::npos)
38     Guard = Guard.substr(PosToolsClang + std::strlen("tools/"));
39 
40   // Unlike LLVM svn, LLVM git monorepo is named llvm-project, so we replace
41   // "/llvm-project/" with the canonical "/llvm/".
42   const static StringRef LLVMProject = "/llvm-project/";
43   size_t PosLLVMProject = Guard.rfind(std::string(LLVMProject));
44   if (PosLLVMProject != StringRef::npos)
45     Guard = Guard.replace(PosLLVMProject, LLVMProject.size(), "/llvm/");
46 
47   // The remainder is LLVM_FULL_PATH_TO_HEADER_H
48   size_t PosLLVM = Guard.rfind("llvm/");
49   if (PosLLVM != StringRef::npos)
50     Guard = Guard.substr(PosLLVM);
51 
52   std::replace(Guard.begin(), Guard.end(), '/', '_');
53   std::replace(Guard.begin(), Guard.end(), '.', '_');
54   std::replace(Guard.begin(), Guard.end(), '-', '_');
55 
56   // The prevalent style in clang is LLVM_CLANG_FOO_BAR_H
57   if (StringRef(Guard).starts_with("clang"))
58     Guard = "LLVM_" + Guard;
59 
60   // The prevalent style in flang is FORTRAN_FOO_BAR_H
61   if (StringRef(Guard).starts_with("flang"))
62     Guard = "FORTRAN" + Guard.substr(sizeof("flang") - 1);
63 
64   return StringRef(Guard).upper();
65 }
66 
67 } // namespace clang::tidy::llvm_check
68