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