brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.5 KiB · 32942e6 Raw
178 lines · cpp
1//===-- ReplayPreambleTests.cpp -------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// These tests cover clangd's logic to replay PP events from preamble to10// clang-tidy checks.11//12//===----------------------------------------------------------------------===//13 14#include "../../clang-tidy/ClangTidyCheck.h"15#include "../../clang-tidy/ClangTidyModule.h"16#include "../../clang-tidy/ClangTidyModuleRegistry.h"17#include "AST.h"18#include "Config.h"19#include "Diagnostics.h"20#include "ParsedAST.h"21#include "SourceCode.h"22#include "TestTU.h"23#include "TidyProvider.h"24#include "support/Context.h"25#include "clang/AST/DeclTemplate.h"26#include "clang/Basic/FileEntry.h"27#include "clang/Basic/LLVM.h"28#include "clang/Basic/SourceLocation.h"29#include "clang/Basic/SourceManager.h"30#include "clang/Basic/TokenKinds.h"31#include "clang/Lex/PPCallbacks.h"32#include "clang/Lex/Token.h"33#include "clang/Tooling/Syntax/Tokens.h"34#include "llvm/ADT/StringRef.h"35#include "llvm/Support/Registry.h"36#include "llvm/Testing/Annotations/Annotations.h"37#include "gmock/gmock-matchers.h"38#include "gmock/gmock.h"39#include "gtest/gtest.h"40#include <cstddef>41#include <memory>42#include <vector>43 44namespace clang {45 46class Module;47 48namespace clangd {49namespace {50struct Inclusion {51  Inclusion(const SourceManager &SM, SourceLocation HashLoc,52            const Token &IncludeTok, llvm::StringRef FileName, bool IsAngled,53            CharSourceRange FilenameRange)54      : HashOffset(SM.getDecomposedLoc(HashLoc).second), IncTok(IncludeTok),55        IncDirective(IncludeTok.getIdentifierInfo()->getName()),56        FileNameOffset(SM.getDecomposedLoc(FilenameRange.getBegin()).second),57        FileName(FileName), IsAngled(IsAngled) {58    EXPECT_EQ(59        toSourceCode(SM, FilenameRange.getAsRange()).drop_back().drop_front(),60        FileName);61  }62  size_t HashOffset;63  syntax::Token IncTok;64  llvm::StringRef IncDirective;65  size_t FileNameOffset;66  llvm::StringRef FileName;67  bool IsAngled;68};69static std::vector<Inclusion> Includes;70static std::vector<syntax::Token> SkippedFiles;71struct ReplayPreamblePPCallback : public PPCallbacks {72  const SourceManager &SM;73  explicit ReplayPreamblePPCallback(const SourceManager &SM) : SM(SM) {}74 75  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,76                          StringRef FileName, bool IsAngled,77                          CharSourceRange FilenameRange, OptionalFileEntryRef,78                          StringRef, StringRef, const clang::Module *, bool,79                          SrcMgr::CharacteristicKind) override {80    Includes.emplace_back(SM, HashLoc, IncludeTok, FileName, IsAngled,81                          FilenameRange);82  }83 84  void FileSkipped(const FileEntryRef &, const Token &FilenameTok,85                   SrcMgr::CharacteristicKind) override {86    SkippedFiles.emplace_back(FilenameTok);87  }88};89struct ReplayPreambleCheck : public tidy::ClangTidyCheck {90  ReplayPreambleCheck(StringRef Name, tidy::ClangTidyContext *Context)91      : ClangTidyCheck(Name, Context) {}92  void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,93                           Preprocessor *ModuleExpanderPP) override {94    PP->addPPCallbacks(::std::make_unique<ReplayPreamblePPCallback>(SM));95  }96};97llvm::StringLiteral CheckName = "replay-preamble-check";98struct ReplayPreambleModule : public tidy::ClangTidyModule {99  void100  addCheckFactories(tidy::ClangTidyCheckFactories &CheckFactories) override {101    CheckFactories.registerCheck<ReplayPreambleCheck>(CheckName);102  }103};104static tidy::ClangTidyModuleRegistry::Add<ReplayPreambleModule>105    X("replay-preamble-module", "");106 107MATCHER_P(rangeIs, R, "") {108  return arg.beginOffset() == R.Begin && arg.endOffset() == R.End;109}110 111TEST(ReplayPreambleTest, IncludesAndSkippedFiles) {112  TestTU TU;113  // This check records inclusion directives replayed by clangd.114  TU.ClangTidyProvider = addTidyChecks(CheckName);115  llvm::Annotations Test(R"cpp(116    $hash^#$include[[import]] $filebegin^"$filerange[[bar.h]]"117    $hash^#$include[[include_next]] $filebegin^"$filerange[[baz.h]]"118    $hash^#$include[[include]] $filebegin^<$filerange[[a.h]]>)cpp");119  llvm::StringRef Code = Test.code();120  TU.Code = Code.str();121  TU.AdditionalFiles["bar.h"] = "";122  TU.AdditionalFiles["baz.h"] = "";123  TU.AdditionalFiles["a.h"] = "";124  // Since we are also testing #import directives, and they don't make much125  // sense in c++ (also they actually break on windows), just set language to126  // obj-c.127  TU.ExtraArgs = {"-isystem.", "-xobjective-c"};128 129  // Allow the check to run even though not marked as fast.130  Config Cfg;131  Cfg.Diagnostics.ClangTidy.FastCheckFilter = Config::FastCheckPolicy::Loose;132  WithContextValue WithCfg(Config::Key, std::move(Cfg));133 134  const auto &AST = TU.build();135  const auto &SM = AST.getSourceManager();136 137  auto HashLocs = Test.points("hash");138  ASSERT_EQ(HashLocs.size(), Includes.size());139  auto IncludeRanges = Test.ranges("include");140  ASSERT_EQ(IncludeRanges.size(), Includes.size());141  auto FileBeginLocs = Test.points("filebegin");142  ASSERT_EQ(FileBeginLocs.size(), Includes.size());143  auto FileRanges = Test.ranges("filerange");144  ASSERT_EQ(FileRanges.size(), Includes.size());145 146  ASSERT_EQ(SkippedFiles.size(), Includes.size());147  for (size_t I = 0; I < Includes.size(); ++I) {148    const auto &Inc = Includes[I];149 150    EXPECT_EQ(Inc.HashOffset, HashLocs[I]);151 152    auto IncRange = IncludeRanges[I];153    EXPECT_THAT(Inc.IncTok.range(SM), rangeIs(IncRange));154    EXPECT_EQ(Inc.IncTok.kind(), tok::identifier);155    EXPECT_EQ(Inc.IncDirective,156              Code.substr(IncRange.Begin, IncRange.End - IncRange.Begin));157 158    EXPECT_EQ(Inc.FileNameOffset, FileBeginLocs[I]);159    EXPECT_EQ(Inc.IsAngled, Code[FileBeginLocs[I]] == '<');160 161    auto FileRange = FileRanges[I];162    EXPECT_EQ(Inc.FileName,163              Code.substr(FileRange.Begin, FileRange.End - FileRange.Begin));164 165    EXPECT_EQ(SM.getDecomposedLoc(SkippedFiles[I].location()).second,166              Inc.FileNameOffset);167    // This also contains quotes/angles so increment the range by one from both168    // sides.169    EXPECT_EQ(170        SkippedFiles[I].text(SM),171        Code.substr(FileRange.Begin - 1, FileRange.End - FileRange.Begin + 2));172    EXPECT_EQ(SkippedFiles[I].kind(), tok::header_name);173  }174}175} // namespace176} // namespace clangd177} // namespace clang178