[PATCH] D54204: [clangd] Initial clang-tidy diagnostics support.

2018-11-16 Thread Sam McCall via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL347036: [clangd] Initial clang-tidy diagnostics support. 
(authored by sammccall, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D54204

Files:
  clang-tools-extra/trunk/clangd/CMakeLists.txt
  clang-tools-extra/trunk/clangd/ClangdUnit.cpp
  clang-tools-extra/trunk/clangd/XRefs.cpp
  clang-tools-extra/trunk/unittests/clangd/ClangdUnitTests.cpp

Index: clang-tools-extra/trunk/unittests/clangd/ClangdUnitTests.cpp
===
--- clang-tools-extra/trunk/unittests/clangd/ClangdUnitTests.cpp
+++ clang-tools-extra/trunk/unittests/clangd/ClangdUnitTests.cpp
@@ -24,6 +24,7 @@
 using testing::Field;
 using testing::IsEmpty;
 using testing::Pair;
+using testing::UnorderedElementsAre;
 
 testing::Matcher WithFix(testing::Matcher FixMatcher) {
   return Field(&Diag::Fixes, ElementsAre(FixMatcher));
@@ -128,6 +129,30 @@
   WithFix(Fix(Test.range(), "int", "change return type to 'int'");
 }
 
+TEST(DiagnosticsTest, ClangTidy) {
+  Annotations Test(R"cpp(
+#define $macrodef[[SQUARE]](X) (X)*(X)
+int main() {
+  return [[sizeof]](sizeof(int));
+  int y = 4;
+  return SQUARE($macroarg[[++]]y);
+}
+  )cpp");
+  auto TU = TestTU::withCode(Test.code());
+  EXPECT_THAT(
+  TU.build().getDiagnostics(),
+  UnorderedElementsAre(
+  Diag(Test.range(), "suspicious usage of 'sizeof(sizeof(...))' "
+ "[bugprone-sizeof-expression]"),
+  AllOf(
+  Diag(Test.range("macroarg"),
+   "side effects in the 1st macro argument 'X' are repeated in "
+   "macro expansion [bugprone-macro-repeated-side-effects]"),
+  WithNote(Diag(Test.range("macrodef"),
+"macro 'SQUARE' defined here "
+"[bugprone-macro-repeated-side-effects]");
+}
+
 TEST(DiagnosticsTest, Preprocessor) {
   // This looks like a preamble, but there's an #else in the middle!
   // Check that:
Index: clang-tools-extra/trunk/clangd/CMakeLists.txt
===
--- clang-tools-extra/trunk/clangd/CMakeLists.txt
+++ clang-tools-extra/trunk/clangd/CMakeLists.txt
@@ -64,6 +64,24 @@
   clangLex
   clangSema
   clangSerialization
+  clangTidy
+  clangTidyAndroidModule
+  clangTidyAbseilModule
+  clangTidyBoostModule
+  clangTidyBugproneModule
+  clangTidyCERTModule
+  clangTidyCppCoreGuidelinesModule
+  clangTidyFuchsiaModule
+  clangTidyGoogleModule
+  clangTidyHICPPModule
+  clangTidyLLVMModule
+  clangTidyMiscModule
+  clangTidyModernizeModule
+  clangTidyObjCModule
+  clangTidyPerformanceModule
+  clangTidyPortabilityModule
+  clangTidyReadabilityModule
+  clangTidyZirconModule
   clangTooling
   clangToolingCore
   clangToolingInclusions
Index: clang-tools-extra/trunk/clangd/XRefs.cpp
===
--- clang-tools-extra/trunk/clangd/XRefs.cpp
+++ clang-tools-extra/trunk/clangd/XRefs.cpp
@@ -672,8 +672,7 @@
 return {};
 
   DeducedTypeVisitor V(SourceLocationBeg);
-  for (Decl *D : AST.getLocalTopLevelDecls())
-V.TraverseDecl(D);
+  V.TraverseAST(AST.getASTContext());
   return V.getDeducedType();
 }
 
Index: clang-tools-extra/trunk/clangd/ClangdUnit.cpp
===
--- clang-tools-extra/trunk/clangd/ClangdUnit.cpp
+++ clang-tools-extra/trunk/clangd/ClangdUnit.cpp
@@ -8,6 +8,8 @@
 //===--===//
 
 #include "ClangdUnit.h"
+#include "../clang-tidy/ClangTidyDiagnosticConsumer.h"
+#include "../clang-tidy/ClangTidyModuleRegistry.h"
 #include "Compiler.h"
 #include "Diagnostics.h"
 #include "Logger.h"
@@ -151,6 +153,40 @@
 return None;
   }
 
+  // Set up ClangTidy. Must happen after BeginSourceFile() so ASTContext exists.
+  // Clang-tidy has some limitiations to ensure reasonable performance:
+  //  - checks don't see all preprocessor events in the preamble
+  //  - matchers run only over the main-file top-level decls (and can't see
+  //ancestors outside this scope).
+  // In practice almost all checks work well without modifications.
+  std::vector> CTChecks;
+  ast_matchers::MatchFinder CTFinder;
+  llvm::Optional CTContext;
+  {
+trace::Span Tracer("ClangTidyInit");
+tidy::ClangTidyCheckFactories CTFactories;
+for (const auto &E : tidy::ClangTidyModuleRegistry::entries())
+  E.instantiate()->addCheckFactories(CTFactories);
+auto CTOpts = tidy::ClangTidyOptions::getDefaults();
+// FIXME: this needs to be configurable, and we need to support .clang-tidy
+// files and other options providers.
+// These checks exercise the matcher- and preprocessor-based hooks.
+CTOpts.Checks =
+"bugprone-sizeof-expre

[PATCH] D54204: [clangd] Initial clang-tidy diagnostics support.

2018-11-15 Thread Haojian Wu via Phabricator via cfe-commits
hokein accepted this revision.
hokein added a comment.
This revision is now accepted and ready to land.

looks good!


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D54204



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D54204: [clangd] Initial clang-tidy diagnostics support.

2018-11-15 Thread Sam McCall via Phabricator via cfe-commits
sammccall updated this revision to Diff 174204.
sammccall added a comment.

Remove clang-tidy changes, add FIXME comment.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D54204

Files:
  clangd/CMakeLists.txt
  clangd/ClangdUnit.cpp
  clangd/XRefs.cpp
  unittests/clangd/ClangdUnitTests.cpp

Index: unittests/clangd/ClangdUnitTests.cpp
===
--- unittests/clangd/ClangdUnitTests.cpp
+++ unittests/clangd/ClangdUnitTests.cpp
@@ -24,6 +24,7 @@
 using testing::Field;
 using testing::IsEmpty;
 using testing::Pair;
+using testing::UnorderedElementsAre;
 
 testing::Matcher WithFix(testing::Matcher FixMatcher) {
   return Field(&Diag::Fixes, ElementsAre(FixMatcher));
@@ -128,6 +129,30 @@
   WithFix(Fix(Test.range(), "int", "change return type to 'int'");
 }
 
+TEST(DiagnosticsTest, ClangTidy) {
+  Annotations Test(R"cpp(
+#define $macrodef[[SQUARE]](X) (X)*(X)
+int main() {
+  return [[sizeof]](sizeof(int));
+  int y = 4;
+  return SQUARE($macroarg[[++]]y);
+}
+  )cpp");
+  auto TU = TestTU::withCode(Test.code());
+  EXPECT_THAT(
+  TU.build().getDiagnostics(),
+  UnorderedElementsAre(
+  Diag(Test.range(), "suspicious usage of 'sizeof(sizeof(...))' "
+ "[bugprone-sizeof-expression]"),
+  AllOf(
+  Diag(Test.range("macroarg"),
+   "side effects in the 1st macro argument 'X' are repeated in "
+   "macro expansion [bugprone-macro-repeated-side-effects]"),
+  WithNote(Diag(Test.range("macrodef"),
+"macro 'SQUARE' defined here "
+"[bugprone-macro-repeated-side-effects]");
+}
+
 TEST(DiagnosticsTest, Preprocessor) {
   // This looks like a preamble, but there's an #else in the middle!
   // Check that:
Index: clangd/XRefs.cpp
===
--- clangd/XRefs.cpp
+++ clangd/XRefs.cpp
@@ -672,8 +672,7 @@
 return {};
 
   DeducedTypeVisitor V(SourceLocationBeg);
-  for (Decl *D : AST.getLocalTopLevelDecls())
-V.TraverseDecl(D);
+  V.TraverseAST(AST.getASTContext());
   return V.getDeducedType();
 }
 
Index: clangd/ClangdUnit.cpp
===
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -8,6 +8,8 @@
 //===--===//
 
 #include "ClangdUnit.h"
+#include "../clang-tidy/ClangTidyDiagnosticConsumer.h"
+#include "../clang-tidy/ClangTidyModuleRegistry.h"
 #include "Compiler.h"
 #include "Diagnostics.h"
 #include "Logger.h"
@@ -151,6 +153,40 @@
 return None;
   }
 
+  // Set up ClangTidy. Must happen after BeginSourceFile() so ASTContext exists.
+  // Clang-tidy has some limitiations to ensure reasonable performance:
+  //  - checks don't see all preprocessor events in the preamble
+  //  - matchers run only over the main-file top-level decls (and can't see
+  //ancestors outside this scope).
+  // In practice almost all checks work well without modifications.
+  std::vector> CTChecks;
+  ast_matchers::MatchFinder CTFinder;
+  llvm::Optional CTContext;
+  {
+trace::Span Tracer("ClangTidyInit");
+tidy::ClangTidyCheckFactories CTFactories;
+for (const auto &E : tidy::ClangTidyModuleRegistry::entries())
+  E.instantiate()->addCheckFactories(CTFactories);
+auto CTOpts = tidy::ClangTidyOptions::getDefaults();
+// FIXME: this needs to be configurable, and we need to support .clang-tidy
+// files and other options providers.
+// These checks exercise the matcher- and preprocessor-based hooks.
+CTOpts.Checks =
+"bugprone-sizeof-expression,bugprone-macro-repeated-side-effects";
+CTContext.emplace(llvm::make_unique(
+tidy::ClangTidyGlobalOptions(), CTOpts));
+CTContext->setDiagnosticsEngine(&Clang->getDiagnostics());
+CTContext->setASTContext(&Clang->getASTContext());
+CTContext->setCurrentFile(MainInput.getFile());
+CTFactories.createChecks(CTContext.getPointer(), CTChecks);
+for (const auto &Check : CTChecks) {
+  // FIXME: the PP callbacks skip the entire preamble.
+  // Checks that want to see #includes in the main file do not see them.
+  Check->registerPPCallbacks(*Clang);
+  Check->registerMatchers(&CTFinder);
+}
+  }
+
   // Copy over the includes from the preamble, then combine with the
   // non-preamble includes below.
   auto Includes = Preamble ? Preamble->Includes : IncludeStructure{};
@@ -160,13 +196,26 @@
   if (!Action->Execute())
 log("Execute() failed when building AST for {0}", MainInput.getFile());
 
+  std::vector ParsedDecls = Action->takeTopLevelDecls();
+  // AST traversals should exclude the preamble, to avoid performance cliffs.
+  Clang->getASTContext().setTraversalScope(ParsedDecls);
+  {
+// Run the AST-dependent part of the clang-tidy che

[PATCH] D54204: [clangd] Initial clang-tidy diagnostics support.

2018-11-15 Thread Sam McCall via Phabricator via cfe-commits
sammccall added a comment.

Moved the clang-tidy changes to https://reviews.llvm.org/D54579.
Sorry for mixing everything up!




Comment at: clang-tidy/readability/SimplifyBooleanExprCheck.cpp:518
 void SimplifyBooleanExprCheck::registerMatchers(MatchFinder *Finder) {
-  Finder->addMatcher(translationUnitDecl().bind("top"), this);
+  Finder->addMatcher(matchOnce(&MatchedOnce), this);
 

hokein wrote:
> maybe add a comment  describing we are trying to find the top level decl?
We're not, we're trying to match any node (but only one). Extended the comment 
on the matcher.



Comment at: clang-tidy/readability/SimplifyBooleanExprCheck.cpp:566
 replaceCompoundReturnWithCondition(Result, Compound, true);
-  else if (const auto TU = Result.Nodes.getNodeAs("top"))
-Visitor(this, Result).TraverseDecl(const_cast(TU));
+  else // MatchOnce matcher
+Visitor(this, Result).TraverseAST(*Result.Context);

hokein wrote:
> add an `assert (MatchOnce)`?
That doesn't compile, I'm not sure what you want here.



Comment at: clangd/ClangdUnit.cpp:158
+  // Clang-tidy has some limitiations to ensure reasonable performance:
+  //  - checks don't see all preprocessor events in the preamble
+  //  - matchers run only over the main-file top-level decls (and can't see

hokein wrote:
> just want to make sure -- do we receive all preprocessor events in the main 
> file when we use preamble? We have a few checks that generate `#include` 
> insertion as part of FixIt.
> 
> `TestTU` doesn't use preamble, it would be nice to have a test running on a 
> main file with a real preamble, but this can be a follow-up I think.
Nope, you're right: `#include` from the preamble are not replayed. Can't fix 
this now, added a FIXME. (Neither of the hardcoded checks care).

TestTU does use a preamble now :-)


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D54204



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D54204: [clangd] Initial clang-tidy diagnostics support.

2018-11-14 Thread Haojian Wu via Phabricator via cfe-commits
hokein added a comment.

Looks mostly good, just a few nits.

This patch contains two parts (clang-tidy and clangd), I think we could split 
into two,  but I'm not insisting, up to you.




Comment at: clang-tidy/modernize/LoopConvertUtils.h:59
 
   /// \brief Run the analysis on the TranslationUnitDecl.
   ///

The comment is out-of-date.



Comment at: clang-tidy/readability/SimplifyBooleanExprCheck.cpp:518
 void SimplifyBooleanExprCheck::registerMatchers(MatchFinder *Finder) {
-  Finder->addMatcher(translationUnitDecl().bind("top"), this);
+  Finder->addMatcher(matchOnce(&MatchedOnce), this);
 

maybe add a comment  describing we are trying to find the top level decl?



Comment at: clang-tidy/readability/SimplifyBooleanExprCheck.cpp:566
 replaceCompoundReturnWithCondition(Result, Compound, true);
-  else if (const auto TU = Result.Nodes.getNodeAs("top"))
-Visitor(this, Result).TraverseDecl(const_cast(TU));
+  else // MatchOnce matcher
+Visitor(this, Result).TraverseAST(*Result.Context);

add an `assert (MatchOnce)`?



Comment at: clang-tidy/readability/SimplifyBooleanExprCheck.h:82
 
+  bool MatchedOnce = false;
   const bool ChainedConditionalReturn;

The name seems a bit unclear for readers without any context, maybe 
`FoundTopDecl`?



Comment at: clangd/ClangdUnit.cpp:158
+  // Clang-tidy has some limitiations to ensure reasonable performance:
+  //  - checks don't see all preprocessor events in the preamble
+  //  - matchers run only over the main-file top-level decls (and can't see

just want to make sure -- do we receive all preprocessor events in the main 
file when we use preamble? We have a few checks that generate `#include` 
insertion as part of FixIt.

`TestTU` doesn't use preamble, it would be nice to have a test running on a 
main file with a real preamble, but this can be a follow-up I think.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D54204



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D54204: [clangd] Initial clang-tidy diagnostics support.

2018-11-09 Thread Sam McCall via Phabricator via cfe-commits
sammccall added inline comments.



Comment at: clangd/ClangdUnit.cpp:175
+CTFactories.createChecks(CTContext.getPointer(), CTChecks);
+for (const auto &Check : CTChecks) {
+  Check->registerPPCallbacks(*Clang);

hokein wrote:
> Maybe add the check names to the `Trace`?
that would be nice, but there's no API to get that info :-(



Comment at: clangd/ClangdUnit.cpp:468
+  X##ModuleAnchorSource
+LINK_TIDY_MODULE(CERT);
+LINK_TIDY_MODULE(Abseil);

hokein wrote:
> I'm curious how much does clangd binary size get increased.
It's now 21M stripped vs 18M before this patch.
The different with debug info is *much* larger for some reason... sadly this 
will hurt link times.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D54204



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D54204: [clangd] Initial clang-tidy diagnostics support.

2018-11-09 Thread Sam McCall via Phabricator via cfe-commits
sammccall updated this revision to Diff 173357.
sammccall marked an inline comment as done.
sammccall added a comment.

Address comments and rebase on https://reviews.llvm.org/D54309, addressing 
performance issues.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D54204

Files:
  clang-tidy/misc/UnusedParametersCheck.cpp
  clang-tidy/modernize/LoopConvertCheck.cpp
  clang-tidy/modernize/LoopConvertUtils.h
  clang-tidy/readability/SimplifyBooleanExprCheck.cpp
  clang-tidy/readability/SimplifyBooleanExprCheck.h
  clangd/CMakeLists.txt
  clangd/ClangdUnit.cpp
  clangd/XRefs.cpp
  unittests/clangd/ClangdUnitTests.cpp

Index: unittests/clangd/ClangdUnitTests.cpp
===
--- unittests/clangd/ClangdUnitTests.cpp
+++ unittests/clangd/ClangdUnitTests.cpp
@@ -24,6 +24,7 @@
 using testing::Field;
 using testing::IsEmpty;
 using testing::Pair;
+using testing::UnorderedElementsAre;
 
 testing::Matcher WithFix(testing::Matcher FixMatcher) {
   return Field(&Diag::Fixes, ElementsAre(FixMatcher));
@@ -128,6 +129,30 @@
   WithFix(Fix(Test.range(), "int", "change return type to 'int'");
 }
 
+TEST(DiagnosticsTest, ClangTidy) {
+  Annotations Test(R"cpp(
+#define $macrodef[[SQUARE]](X) (X)*(X)
+int main() {
+  return [[sizeof]](sizeof(int));
+  int y = 4;
+  return SQUARE($macroarg[[++]]y);
+}
+  )cpp");
+  auto TU = TestTU::withCode(Test.code());
+  EXPECT_THAT(
+  TU.build().getDiagnostics(),
+  UnorderedElementsAre(
+  Diag(Test.range(), "suspicious usage of 'sizeof(sizeof(...))' "
+ "[bugprone-sizeof-expression]"),
+  AllOf(
+  Diag(Test.range("macroarg"),
+   "side effects in the 1st macro argument 'X' are repeated in "
+   "macro expansion [bugprone-macro-repeated-side-effects]"),
+  WithNote(Diag(Test.range("macrodef"),
+"macro 'SQUARE' defined here "
+"[bugprone-macro-repeated-side-effects]");
+}
+
 TEST(DiagnosticsTest, Preprocessor) {
   // This looks like a preamble, but there's an #else in the middle!
   // Check that:
Index: clangd/XRefs.cpp
===
--- clangd/XRefs.cpp
+++ clangd/XRefs.cpp
@@ -672,8 +672,7 @@
 return {};
 
   DeducedTypeVisitor V(SourceLocationBeg);
-  for (Decl *D : AST.getLocalTopLevelDecls())
-V.TraverseDecl(D);
+  V.TraverseAST(AST.getASTContext());
   return V.getDeducedType();
 }
 
Index: clangd/ClangdUnit.cpp
===
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -8,6 +8,8 @@
 //===--===//
 
 #include "ClangdUnit.h"
+#include "../clang-tidy/ClangTidyDiagnosticConsumer.h"
+#include "../clang-tidy/ClangTidyModuleRegistry.h"
 #include "Compiler.h"
 #include "Diagnostics.h"
 #include "Logger.h"
@@ -151,6 +153,38 @@
 return None;
   }
 
+  // Set up ClangTidy. Must happen after BeginSourceFile() so ASTContext exists.
+  // Clang-tidy has some limitiations to ensure reasonable performance:
+  //  - checks don't see all preprocessor events in the preamble
+  //  - matchers run only over the main-file top-level decls (and can't see
+  //ancestors outside this scope).
+  // In practice almost all checks work well without modifications.
+  std::vector> CTChecks;
+  ast_matchers::MatchFinder CTFinder;
+  llvm::Optional CTContext;
+  {
+trace::Span Tracer("ClangTidyInit");
+tidy::ClangTidyCheckFactories CTFactories;
+for (const auto &E : tidy::ClangTidyModuleRegistry::entries())
+  E.instantiate()->addCheckFactories(CTFactories);
+auto CTOpts = tidy::ClangTidyOptions::getDefaults();
+// FIXME: this needs to be configurable, and we need to support .clang-tidy
+// files and other options providers.
+// These checks exercise the matcher- and preprocessor-based hooks.
+CTOpts.Checks =
+"bugprone-sizeof-expression,bugprone-macro-repeated-side-effects";
+CTContext.emplace(llvm::make_unique(
+tidy::ClangTidyGlobalOptions(), CTOpts));
+CTContext->setDiagnosticsEngine(&Clang->getDiagnostics());
+CTContext->setASTContext(&Clang->getASTContext());
+CTContext->setCurrentFile(MainInput.getFile());
+CTFactories.createChecks(CTContext.getPointer(), CTChecks);
+for (const auto &Check : CTChecks) {
+  Check->registerPPCallbacks(*Clang);
+  Check->registerMatchers(&CTFinder);
+}
+  }
+
   // Copy over the includes from the preamble, then combine with the
   // non-preamble includes below.
   auto Includes = Preamble ? Preamble->Includes : IncludeStructure{};
@@ -160,13 +194,26 @@
   if (!Action->Execute())
 log("Execute() failed when building AST for {0}", MainInput.getFile());
 
+  std::vector ParsedDecls = Action->takeTopLevelDecls();
+  // 

[PATCH] D54204: [clangd] Initial clang-tidy diagnostics support.

2018-11-07 Thread Haojian Wu via Phabricator via cfe-commits
hokein added a comment.

I think this is in a good shape as initial patch!




Comment at: clangd/ClangdUnit.cpp:168
+// The placeholder check here does not use hasAncestor() so is unaffected.
+CTOpts.Checks = "bugprone-sizeof-expression";
+CTContext.emplace(llvm::make_unique(

It seems we also support clang-tidy checks that analyze preprocessor-dependent 
properties. I think we can add a clang-tidy check to make sure `PPCallback` 
actually work, `google-readability-todo` is a good candidate. 

Ah just realized limitations (truncated `PPCallback` events) you wrote in the 
patch description, maybe mention them in the source comment, so that we won't 
forget in the future when reading the code.



Comment at: clangd/ClangdUnit.cpp:175
+CTFactories.createChecks(CTContext.getPointer(), CTChecks);
+for (const auto &Check : CTChecks) {
+  Check->registerPPCallbacks(*Clang);

Maybe add the check names to the `Trace`?



Comment at: clangd/ClangdUnit.cpp:468
+  X##ModuleAnchorSource
+LINK_TIDY_MODULE(CERT);
+LINK_TIDY_MODULE(Abseil);

I'm curious how much does clangd binary size get increased.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D54204



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D54204: [clangd] Initial clang-tidy diagnostics support.

2018-11-07 Thread Sam McCall via Phabricator via cfe-commits
sammccall created this revision.
sammccall added a reviewer: hokein.
Herald added subscribers: cfe-commits, kadircet, arphaman, jkorous, MaskRay, 
ioeric, ilya-biryukov, mgorny, srhines.

This runs checks over a restricted subset of the TU:

- preprocessor callbacks just receive the truncated PP events that occur when a 
preamble is used.
- ASTMatchers run only over the top-level decls in the main-file

This patch just turns on one simple check (bugprone-sizeof-expression)
with no configuration.

- configuration is complex enough to warrant a separate patch
- arbitrary checks don't work well yet - there are various ways that checks can 
access the whole AST (and thus be incredibly slow). Most notably: the 
hasAncestor matcher, and using the ASTContext from check().

This depends on a small patch to ASTMatchers to run a MatchFinder on a
certain set of top-level declarations.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D54204

Files:
  clangd/CMakeLists.txt
  clangd/ClangdUnit.cpp
  unittests/clangd/ClangdUnitTests.cpp

Index: unittests/clangd/ClangdUnitTests.cpp
===
--- unittests/clangd/ClangdUnitTests.cpp
+++ unittests/clangd/ClangdUnitTests.cpp
@@ -128,6 +128,15 @@
   WithFix(Fix(Test.range(), "int", "change return type to 'int'");
 }
 
+TEST(DiagnosticsTest, ClangTidy) {
+  Annotations Test("int main() { return [[sizeof]](sizeof(int)); }");
+  auto TU = TestTU::withCode(Test.code());
+  EXPECT_THAT(TU.build().getDiagnostics(),
+  ElementsAre(Diag(Test.range(),
+   "suspicious usage of 'sizeof(sizeof(...))' "
+   "[bugprone-sizeof-expression]")));
+}
+
 TEST(DiagnosticsTest, Preprocessor) {
   // This looks like a preamble, but there's an #else in the middle!
   // Check that:
Index: clangd/ClangdUnit.cpp
===
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -8,6 +8,8 @@
 //===--===//
 
 #include "ClangdUnit.h"
+#include "../clang-tidy/ClangTidyDiagnosticConsumer.h"
+#include "../clang-tidy/ClangTidyModuleRegistry.h"
 #include "Compiler.h"
 #include "Diagnostics.h"
 #include "Logger.h"
@@ -148,6 +150,34 @@
 return None;
   }
 
+  // Set up ClangTidy. Must happen after BeginSourceFile() so ASTContext exists.
+  std::vector> CTChecks;
+  ast_matchers::MatchFinder CTFinder;
+  llvm::Optional CTContext;
+  {
+trace::Span Tracer("ClangTidyInit");
+tidy::ClangTidyCheckFactories CTFactories;
+for (const auto &E : tidy::ClangTidyModuleRegistry::entries())
+  E.instantiate()->addCheckFactories(CTFactories);
+auto CTOpts = tidy::ClangTidyOptions::getDefaults();
+// FIXME: this needs to be configurable, and we need to support .clang-tidy
+// files and other options providers.
+// There is an important bug to fix before turning on arbitrary checks:
+// we must restrict the AST parent map to the current file for performance.
+// The placeholder check here does not use hasAncestor() so is unaffected.
+CTOpts.Checks = "bugprone-sizeof-expression";
+CTContext.emplace(llvm::make_unique(
+tidy::ClangTidyGlobalOptions(), CTOpts));
+CTContext->setDiagnosticsEngine(&Clang->getDiagnostics());
+CTContext->setASTContext(&Clang->getASTContext());
+CTContext->setCurrentFile(MainInput.getFile());
+CTFactories.createChecks(CTContext.getPointer(), CTChecks);
+for (const auto &Check : CTChecks) {
+  Check->registerPPCallbacks(*Clang);
+  Check->registerMatchers(&CTFinder);
+}
+  }
+
   // Copy over the includes from the preamble, then combine with the
   // non-preamble includes below.
   auto Includes = Preamble ? Preamble->Includes : IncludeStructure{};
@@ -157,13 +187,24 @@
   if (!Action->Execute())
 log("Execute() failed when building AST for {0}", MainInput.getFile());
 
+  std::vector ParsedDecls = Action->takeTopLevelDecls();
+  {
+// Run the AST-dependent part of the clang-tidy checks.
+// (The preprocessor part ran already, via PPCallbacks).
+trace::Span Tracer("ClangTidyMatch");
+CTFinder.matchAST(Clang->getASTContext(), ParsedDecls);
+  }
+
   // UnitDiagsConsumer is local, we can not store it in CompilerInstance that
   // has a longer lifetime.
   Clang->getDiagnostics().setClient(new IgnoreDiagnostics);
   // CompilerInstance won't run this callback, do it directly.
   ASTDiags.EndSourceFile();
+  // XXX: This is messy: clang-tidy checks flush some diagnostics at EOF.
+  // However Action->EndSourceFile() would destroy the ASTContext!
+  // So just inform the preprocessor of EOF, while keeping everything alive.
+  Clang->getPreprocessor().EndSourceFile();
 
-  std::vector ParsedDecls = Action->takeTopLevelDecls();
   std::vector Diags = ASTDiags.take();
   // Add diagnostics from the preamble, if any.
   if (Pream