1 //===--- KernelNameRestrictionCheck.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 "KernelNameRestrictionCheck.h"
10 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/Lex/PPCallbacks.h"
12 #include "clang/Lex/Preprocessor.h"
13 #include <string>
14 #include <vector>
15
16 using namespace clang::ast_matchers;
17
18 namespace clang {
19 namespace tidy {
20 namespace altera {
21
22 namespace {
23
24 class KernelNameRestrictionPPCallbacks : public PPCallbacks {
25 public:
KernelNameRestrictionPPCallbacks(ClangTidyCheck & Check,const SourceManager & SM)26 explicit KernelNameRestrictionPPCallbacks(ClangTidyCheck &Check,
27 const SourceManager &SM)
28 : Check(Check), SM(SM) {}
29
30 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
31 StringRef FileName, bool IsAngled,
32 CharSourceRange FileNameRange, const FileEntry *File,
33 StringRef SearchPath, StringRef RelativePath,
34 const Module *Imported,
35 SrcMgr::CharacteristicKind FileType) override;
36
37 void EndOfMainFile() override;
38
39 private:
40 /// Returns true if the name of the file with path FilePath is 'kernel.cl',
41 /// 'verilog.cl', or 'vhdl.cl'. The file name check is case insensitive.
42 bool FileNameIsRestricted(StringRef FilePath);
43
44 struct IncludeDirective {
45 SourceLocation Loc; // Location in the include directive.
46 StringRef FileName; // Filename as a string.
47 };
48
49 std::vector<IncludeDirective> IncludeDirectives;
50 ClangTidyCheck &Check;
51 const SourceManager &SM;
52 };
53
54 } // namespace
55
registerPPCallbacks(const SourceManager & SM,Preprocessor * PP,Preprocessor *)56 void KernelNameRestrictionCheck::registerPPCallbacks(const SourceManager &SM,
57 Preprocessor *PP,
58 Preprocessor *) {
59 PP->addPPCallbacks(
60 std::make_unique<KernelNameRestrictionPPCallbacks>(*this, SM));
61 }
62
InclusionDirective(SourceLocation HashLoc,const Token &,StringRef FileName,bool,CharSourceRange,const FileEntry *,StringRef,StringRef,const Module *,SrcMgr::CharacteristicKind)63 void KernelNameRestrictionPPCallbacks::InclusionDirective(
64 SourceLocation HashLoc, const Token &, StringRef FileName, bool,
65 CharSourceRange, const FileEntry *, StringRef, StringRef, const Module *,
66 SrcMgr::CharacteristicKind) {
67 IncludeDirective ID = {HashLoc, FileName};
68 IncludeDirectives.push_back(std::move(ID));
69 }
70
FileNameIsRestricted(StringRef FileName)71 bool KernelNameRestrictionPPCallbacks::FileNameIsRestricted(
72 StringRef FileName) {
73 return FileName.equals_lower("kernel.cl") ||
74 FileName.equals_lower("verilog.cl") ||
75 FileName.equals_lower("vhdl.cl");
76 }
77
EndOfMainFile()78 void KernelNameRestrictionPPCallbacks::EndOfMainFile() {
79
80 // Check main file for restricted names.
81 const FileEntry *Entry = SM.getFileEntryForID(SM.getMainFileID());
82 StringRef FileName = llvm::sys::path::filename(Entry->getName());
83 if (FileNameIsRestricted(FileName))
84 Check.diag(SM.getLocForStartOfFile(SM.getMainFileID()),
85 "compiling '%0' may cause additional compilation errors due "
86 "to the name of the kernel source file; consider renaming the "
87 "included kernel source file")
88 << FileName;
89
90 if (IncludeDirectives.empty())
91 return;
92
93 // Check included files for restricted names.
94 for (const IncludeDirective &ID : IncludeDirectives) {
95 StringRef FileName = llvm::sys::path::filename(ID.FileName);
96 if (FileNameIsRestricted(FileName))
97 Check.diag(ID.Loc,
98 "including '%0' may cause additional compilation errors due "
99 "to the name of the kernel source file; consider renaming the "
100 "included kernel source file")
101 << FileName;
102 }
103 }
104
105 } // namespace altera
106 } // namespace tidy
107 } // namespace clang
108