nik updated this revision to Diff 143738.
nik marked 2 inline comments as done.
nik added a comment.
Herald added a subscriber: eraman.
Addressed inline comments.


Repository:
  rC Clang

https://reviews.llvm.org/D45815

Files:
  include/clang-c/Index.h
  include/clang/Frontend/ASTUnit.h
  include/clang/Frontend/FrontendOptions.h
  include/clang/Frontend/SkipFunctionBodies.h
  include/clang/Parse/ParseAST.h
  include/clang/Parse/Parser.h
  lib/Frontend/ASTUnit.cpp
  lib/Parse/ParseAST.cpp
  lib/Parse/ParseCXXInlineMethods.cpp
  lib/Parse/ParseObjc.cpp
  lib/Parse/Parser.cpp
  test/Parser/skip-function-bodies.h
  test/Parser/skip-function-bodies.mm
  tools/c-index-test/c-index-test.c
  tools/libclang/CIndex.cpp
  tools/libclang/Indexing.cpp
  unittests/CodeGen/BufferSourceTest.cpp
  unittests/CodeGen/CodeGenExternalTest.cpp
  unittests/CodeGen/IncrementalProcessingTest.cpp
  unittests/CodeGen/TBAAMetadataTest.cpp
  unittests/Frontend/PCHPreambleTest.cpp
  unittests/Lex/PPCallbacksTest.cpp
  unittests/Tooling/ToolingTest.cpp

Index: unittests/Tooling/ToolingTest.cpp
===================================================================
--- unittests/Tooling/ToolingTest.cpp
+++ unittests/Tooling/ToolingTest.cpp
@@ -250,7 +250,7 @@
 struct SkipBodyAction : public clang::ASTFrontendAction {
   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
                                                  StringRef) override {
-    Compiler.getFrontendOpts().SkipFunctionBodies = true;
+    Compiler.getFrontendOpts().SkipFunctionBodies = SkipFunctionBodiesKind::All;
     return llvm::make_unique<SkipBodyConsumer>();
   }
 };
Index: unittests/Lex/PPCallbacksTest.cpp
===================================================================
--- unittests/Lex/PPCallbacksTest.cpp
+++ unittests/Lex/PPCallbacksTest.cpp
@@ -201,7 +201,7 @@
 
     ASTConsumer Consumer;
     Sema S(PP, Context, Consumer);
-    Parser P(PP, S, false);
+    Parser P(PP, S, SkipFunctionBodiesKind::None);
     PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
     PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
 
Index: unittests/Frontend/PCHPreambleTest.cpp
===================================================================
--- unittests/Frontend/PCHPreambleTest.cpp
+++ unittests/Frontend/PCHPreambleTest.cpp
@@ -103,7 +103,9 @@
   }
 
   bool ReparseAST(const std::unique_ptr<ASTUnit> &AST) {
-    bool reparseFailed = AST->Reparse(PCHContainerOpts, GetRemappedFiles(), VFS);
+    bool reparseFailed =
+        AST->Reparse(PCHContainerOpts, GetRemappedFiles(),
+                     ASTUnit::SkipFunctionBodiesOptions(), VFS);
     return !reparseFailed;
   }
 
Index: unittests/CodeGen/TBAAMetadataTest.cpp
===================================================================
--- unittests/CodeGen/TBAAMetadataTest.cpp
+++ unittests/CodeGen/TBAAMetadataTest.cpp
@@ -73,7 +73,7 @@
   }
 
   const BasicBlock *compile() {
-    clang::ParseAST(compiler.getSema(), false, false);
+    clang::ParseAST(compiler.getSema(), false, clang::SkipFunctionBodiesKind::None);
     M = CG->GetModule();
 
     // Do not expect more than one function definition.
Index: unittests/CodeGen/IncrementalProcessingTest.cpp
===================================================================
--- unittests/CodeGen/IncrementalProcessingTest.cpp
+++ unittests/CodeGen/IncrementalProcessingTest.cpp
@@ -143,7 +143,7 @@
     Sema& S = compiler.getSema();
 
     std::unique_ptr<Parser> ParseOP(new Parser(S.getPreprocessor(), S,
-                                               /*SkipFunctionBodies*/ false));
+                                               SkipFunctionBodiesKind::None));
     Parser &P = *ParseOP.get();
 
     std::array<std::unique_ptr<llvm::Module>, 3> M;
Index: unittests/CodeGen/CodeGenExternalTest.cpp
===================================================================
--- unittests/CodeGen/CodeGenExternalTest.cpp
+++ unittests/CodeGen/CodeGenExternalTest.cpp
@@ -294,7 +294,7 @@
     sm.setMainFileID(sm.createFileID(
         llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User));
 
-    clang::ParseAST(compiler.getSema(), false, false);
+    clang::ParseAST(compiler.getSema(), false, clang::SkipFunctionBodiesKind::None);
 
     ASSERT_TRUE(test_codegen_fns_ran);
 }
Index: unittests/CodeGen/BufferSourceTest.cpp
===================================================================
--- unittests/CodeGen/BufferSourceTest.cpp
+++ unittests/CodeGen/BufferSourceTest.cpp
@@ -74,7 +74,7 @@
     sm.setMainFileID(sm.createFileID(
         llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User));
 
-    clang::ParseAST(compiler.getSema(), false, false);
+    clang::ParseAST(compiler.getSema(), false, clang::SkipFunctionBodiesKind::None);
 }
 
 } // end anonymous namespace
Index: tools/libclang/Indexing.cpp
===================================================================
--- tools/libclang/Indexing.cpp
+++ tools/libclang/Indexing.cpp
@@ -540,7 +540,7 @@
   bool SkipBodies = (index_options & CXIndexOpt_SkipParsedBodiesInSession) &&
       CInvok->getLangOpts()->CPlusPlus;
   if (SkipBodies)
-    CInvok->getFrontendOpts().SkipFunctionBodies = true;
+    CInvok->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodiesKind::All;
 
   auto DataConsumer =
     std::make_shared<CXIndexDataConsumer>(client_data, CB, index_options,
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -3346,6 +3346,20 @@
                                     Options);
 }
 
+static ASTUnit::SkipFunctionBodiesOptions
+skipFunctionBodiesOptionsFromParseOptions(unsigned options) {
+  ASTUnit::SkipFunctionBodiesOptions SkipFunctionBodiesOpts;
+  if (options & CXTranslationUnit_SkipFunctionBodies) {
+      if (options & CXTranslationUnit_LimitSkipFunctionBodiesToNonTemplates)
+        SkipFunctionBodiesOpts.LimitToNonTemplateFunctions = true;
+      SkipFunctionBodiesOpts.Scope =
+          (options & CXTranslationUnit_LimitSkipFunctionBodiesToPreamble)
+              ? ASTUnit::SkipFunctionBodiesOptions::Preamble
+              : ASTUnit::SkipFunctionBodiesOptions::MainFileAndPreamble;
+  }
+  return SkipFunctionBodiesOpts;
+}
+
 static CXErrorCode
 clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
                                 const char *const *command_line_args,
@@ -3376,9 +3390,10 @@
     = options & CXTranslationUnit_CacheCompletionResults;
   bool IncludeBriefCommentsInCodeCompletion
     = options & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
-  bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies;
   bool SingleFileParse = options & CXTranslationUnit_SingleFileParse;
   bool ForSerialization = options & CXTranslationUnit_ForSerialization;
+  ASTUnit::SkipFunctionBodiesOptions SkipFunctionBodiesOpts =
+      skipFunctionBodiesOptionsFromParseOptions(options);
 
   // Configure the diagnostics.
   IntrusiveRefCntPtr<DiagnosticsEngine>
@@ -3467,7 +3482,7 @@
       /*CaptureDiagnostics=*/true, *RemappedFiles.get(),
       /*RemappedFilesKeepOriginalName=*/true, PrecompilePreambleAfterNParses,
       TUKind, CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion,
-      /*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodies, SingleFileParse,
+      /*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodiesOpts, SingleFileParse,
       /*UserFilesAreVolatile=*/true, ForSerialization,
       CXXIdx->getPCHContainerOperations()->getRawReader().getFormat(),
       &ErrUnit));
@@ -4055,7 +4070,8 @@
   }
 
   if (!CXXUnit->Reparse(CXXIdx->getPCHContainerOperations(),
-                        *RemappedFiles.get()))
+                        *RemappedFiles.get(),
+                        skipFunctionBodiesOptionsFromParseOptions(TU->ParsingOptions)))
     return CXError_Success;
   if (isASTReadError(CXXUnit))
     return CXError_ASTReadError;
Index: tools/c-index-test/c-index-test.c
===================================================================
--- tools/c-index-test/c-index-test.c
+++ tools/c-index-test/c-index-test.c
@@ -82,6 +82,10 @@
     options |= CXTranslationUnit_CreatePreambleOnFirstParse;
   if (getenv("CINDEXTEST_KEEP_GOING"))
     options |= CXTranslationUnit_KeepGoing;
+  if (getenv("CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_PREAMBLE"))
+    options |= CXTranslationUnit_LimitSkipFunctionBodiesToPreamble;
+  if (getenv("CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_NON_TEMPLATES"))
+    options |= CXTranslationUnit_LimitSkipFunctionBodiesToNonTemplates;
 
   return options;
 }
Index: test/Parser/skip-function-bodies.mm
===================================================================
--- test/Parser/skip-function-bodies.mm
+++ test/Parser/skip-function-bodies.mm
@@ -1,4 +1,4 @@
-// RUN: env CINDEXTEST_SKIP_FUNCTION_BODIES=1 c-index-test -test-load-source all %s | FileCheck %s
+#include "skip-function-bodies.h"
 
 class A {
   class B {};
@@ -27,6 +27,12 @@
   class K {};
 }
 
+template <typename T>
+T g(T t) {
+  return t;
+}
+
+// RUN: env CINDEXTEST_SKIP_FUNCTION_BODIES=1 c-index-test -test-load-source all %s | FileCheck %s
 // CHECK: skip-function-bodies.mm:3:7: ClassDecl=A:3:7 (Definition) Extent=[3:1 - 14:2]
 // CHECK: skip-function-bodies.mm:4:9: ClassDecl=B:4:9 (Definition) Extent=[4:3 - 4:13]
 // CHECK: skip-function-bodies.mm:6:1: CXXAccessSpecifier=:6:1 (Definition) Extent=[6:1 - 6:8]
@@ -43,3 +49,48 @@
 // CHECK-NOT: skip-function-bodies.mm:21:11: TypeRef=class A:3:7 Extent=[21:11 - 21:12]
 // CHECK: skip-function-bodies.mm:26:6: FunctionDecl=J:26:6 Extent=[26:1 - 26:9]
 // CHECK-NOT: skip-function-bodies.mm:27:9: ClassDecl=K:27:9 (Definition) Extent=[27:3 - 27:13]
+// CHECK: skip-function-bodies.mm:31:3: FunctionTemplate=g:31:3 Extent=[30:1 - 31:9]
+// CHECK: skip-function-bodies.mm:30:20: TemplateTypeParameter=T:30:20 (Definition) Extent=[30:11 - 30:21] [access=public]
+// CHECK: skip-function-bodies.mm:31:1: TypeRef=T:30:20 Extent=[31:1 - 31:2]
+// CHECK: skip-function-bodies.mm:31:7: ParmDecl=t:31:7 (Definition) Extent=[31:5 - 31:8]
+// CHECK: skip-function-bodies.mm:31:5: TypeRef=T:30:20 Extent=[31:5 - 31:6]
+// CHECK-NOT: skip-function-bodies.mm:31:10: CompoundStmt= Extent=[31:10 - 33:2]
+// CHECK-NOT: skip-function-bodies.mm:32:3: ReturnStmt= Extent=[32:3 - 32:11]
+// CHECK-NOT: skip-function-bodies.mm:32:10: DeclRefExpr=t:31:7 Extent=[32:10 - 32:11]
+
+// RUN: env CINDEXTEST_SKIP_FUNCTION_BODIES=1 \
+// RUN:  CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_NON_TEMPLATES=1 \
+// RUN:  c-index-test -test-load-source all %s | FileCheck -check-prefix=CHECK-TEMPLATES %s
+// CHECK-TEMPLATES-NOT: skip-function-bodies.mm:8:12: StructDecl=C:8:12 (Definition) Extent=[8:5 - 10:6]
+// CHECK-TEMPLATES-NOT: skip-function-bodies.mm:9:12: CXXMethod=d:9:12 (Definition) Extent=[9:7 - 9:18]
+// CHECK-TEMPLATES: skip-function-bodies.mm:31:3: FunctionTemplate=g:31:3 (Definition) Extent=[30:1 - 33:2]
+// CHECK-TEMPLATES: skip-function-bodies.mm:30:20: TemplateTypeParameter=T:30:20 (Definition) Extent=[30:11 - 30:21] [access=public]
+// CHECK-TEMPLATES: skip-function-bodies.mm:31:1: TypeRef=T:30:20 Extent=[31:1 - 31:2]
+// CHECK-TEMPLATES: skip-function-bodies.mm:31:7: ParmDecl=t:31:7 (Definition) Extent=[31:5 - 31:8]
+// CHECK-TEMPLATES: skip-function-bodies.mm:31:5: TypeRef=T:30:20 Extent=[31:5 - 31:6]
+// CHECK-TEMPLATES: skip-function-bodies.mm:31:10: CompoundStmt= Extent=[31:10 - 33:2]
+// CHECK-TEMPLATES: skip-function-bodies.mm:32:3: ReturnStmt= Extent=[32:3 - 32:11]
+// CHECK-TEMPLATES: skip-function-bodies.mm:32:10: DeclRefExpr=t:31:7 Extent=[32:10 - 32:11]
+
+// RUN: env CINDEXTEST_EDITING=1 \
+// RUN:  CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE=1 \
+// RUN:  CINDEXTEST_SKIP_FUNCTION_BODIES=1 \
+// RUN:  CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_PREAMBLE=1 \
+// RUN:  c-index-test -test-load-source all %s | FileCheck -check-prefix=CHECK-PREAMBLE1 %s
+// CHECK-PREAMBLE1: skip-function-bodies.h:1:5: FunctionDecl=header1:1:5 Extent=[1:1 - 1:19]
+// CHECK-PREAMBLE1-NOT: skip-function-bodies.h:2:3: ReturnStmt= Extent=[2:3 - 2:11]
+// CHECK-PREAMBLE1: skip-function-bodies.mm:8:12: StructDecl=C:8:12 (Definition) Extent=[8:5 - 10:6]
+// CHECK-PREAMBLE1: skip-function-bodies.mm:9:12: CXXMethod=d:9:12 (Definition) Extent=[9:7 - 9:18]
+
+// RUN: env CINDEXTEST_EDITING=1 \
+// RUN:  CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE=1 \
+// RUN:  CINDEXTEST_SKIP_FUNCTION_BODIES=1 \
+// RUN:  CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_PREAMBLE=1 \
+// RUN:  CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_NON_TEMPLATES=1 \
+// RUN:  c-index-test -test-load-source all %s | FileCheck -check-prefix=CHECK-PREAMBLE2 %s
+// CHECK-PREAMBLE2: skip-function-bodies.h:1:5: FunctionDecl=header1:1:5 Extent=[1:1 - 1:19]
+// CHECK-PREAMBLE2-NOT: skip-function-bodies.h:2:3: ReturnStmt= Extent=[2:3 - 2:11]
+// CHECK-PREAMBLE2: skip-function-bodies.h:6:3: FunctionTemplate=header2:6:3 (Definition) Extent=[5:1 - 8:2]
+// CHECK-PREAMBLE2: skip-function-bodies.h:7:3: ReturnStmt= Extent=[7:3 - 7:11]
+// CHECK-PREAMBLE2: skip-function-bodies.mm:8:12: StructDecl=C:8:12 (Definition) Extent=[8:5 - 10:6]
+// CHECK-PREAMBLE2: skip-function-bodies.mm:9:12: CXXMethod=d:9:12 (Definition) Extent=[9:7 - 9:18]
Index: test/Parser/skip-function-bodies.h
===================================================================
--- /dev/null
+++ test/Parser/skip-function-bodies.h
@@ -0,0 +1,8 @@
+int header1(int t) {
+  return t;
+}
+
+template <typename T>
+T header2(T t) {
+  return t;
+}
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -47,12 +47,17 @@
   return Ident__except;
 }
 
-Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
-  : PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
-    GreaterThanIsOperator(true), ColonIsSacred(false), 
-    InMessageExpression(false), TemplateParameterDepth(0),
-    ParsingInObjCContainer(false) {
-  SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies;
+Parser::Parser(Preprocessor &pp, Sema &actions,
+               SkipFunctionBodiesKind skipFunctionBodies)
+    : PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
+      GreaterThanIsOperator(true), ColonIsSacred(false),
+      InMessageExpression(false), TemplateParameterDepth(0),
+      ParsingInObjCContainer(false) {
+
+  if (pp.isCodeCompletionEnabled())
+    SkipFunctionBodies = SkipFunctionBodiesKind::All;
+  else
+    SkipFunctionBodies = skipFunctionBodies;
   Tok.startToken();
   Tok.setKind(tok::eof);
   Actions.CurScope = nullptr;
@@ -1100,6 +1105,19 @@
     }
   }
 
+  bool ShouldSkipFunctionBody = false;
+  switch (SkipFunctionBodies) {
+  case SkipFunctionBodiesKind::All:
+    ShouldSkipFunctionBody = true;
+    break;
+  case SkipFunctionBodiesKind::AllExceptTemplates:
+    ShouldSkipFunctionBody = TemplateInfo.Kind != ParsedTemplateInfo::Template;
+    break;
+  case SkipFunctionBodiesKind::None:
+  default:
+    ShouldSkipFunctionBody = false;
+  }
+
   // In delayed template parsing mode, for function template we consume the
   // tokens and store them for late parsing at the end of the translation unit.
   if (getLangOpts().DelayedTemplateParsing && Tok.isNot(tok::equal) &&
@@ -1117,7 +1135,7 @@
     D.complete(DP);
     D.getMutableDeclSpec().abort();
 
-    if (SkipFunctionBodies && (!DP || Actions.canSkipFunctionBody(DP)) &&
+    if (ShouldSkipFunctionBody && (!DP || Actions.canSkipFunctionBody(DP)) &&
         trySkippingFunctionBody()) {
       BodyScope.Exit();
       return Actions.ActOnSkippedFunctionBody(DP);
@@ -1217,7 +1235,7 @@
     return Res;
   }
 
-  if (SkipFunctionBodies && (!Res || Actions.canSkipFunctionBody(Res)) &&
+  if (ShouldSkipFunctionBody && (!Res || Actions.canSkipFunctionBody(Res)) &&
       trySkippingFunctionBody()) {
     BodyScope.Exit();
     Actions.ActOnSkippedFunctionBody(Res);
Index: lib/Parse/ParseObjc.cpp
===================================================================
--- lib/Parse/ParseObjc.cpp
+++ lib/Parse/ParseObjc.cpp
@@ -2634,7 +2634,8 @@
 /// StashAwayMethodOrFunctionBodyTokens -  Consume the tokens and store them 
 /// for later parsing.
 void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) {
-  if (SkipFunctionBodies && (!MDecl || Actions.canSkipFunctionBody(MDecl)) &&
+  if (SkipFunctionBodies != SkipFunctionBodiesKind::None &&
+      (!MDecl || Actions.canSkipFunctionBody(MDecl)) &&
       trySkippingFunctionBody()) {
     Actions.ActOnSkippedFunctionBody(MDecl);
     return;
Index: lib/Parse/ParseCXXInlineMethods.cpp
===================================================================
--- lib/Parse/ParseCXXInlineMethods.cpp
+++ lib/Parse/ParseCXXInlineMethods.cpp
@@ -101,8 +101,8 @@
     return FnD;
   }
 
-  if (SkipFunctionBodies && (!FnD || Actions.canSkipFunctionBody(FnD)) &&
-      trySkippingFunctionBody()) {
+  if (SkipFunctionBodies != SkipFunctionBodiesKind::None &&
+      (!FnD || Actions.canSkipFunctionBody(FnD)) && trySkippingFunctionBody()) {
     Actions.ActOnSkippedFunctionBody(FnD);
     return FnD;
   }
Index: lib/Parse/ParseAST.cpp
===================================================================
--- lib/Parse/ParseAST.cpp
+++ lib/Parse/ParseAST.cpp
@@ -100,7 +100,7 @@
                      ASTContext &Ctx, bool PrintStats,
                      TranslationUnitKind TUKind,
                      CodeCompleteConsumer *CompletionConsumer,
-                     bool SkipFunctionBodies) {
+                     SkipFunctionBodiesKind SkipFunctionBodies) {
 
   std::unique_ptr<Sema> S(
       new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer));
@@ -111,7 +111,8 @@
   ParseAST(*S.get(), PrintStats, SkipFunctionBodies);
 }
 
-void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
+void clang::ParseAST(Sema &S, bool PrintStats,
+                     SkipFunctionBodiesKind SkipFunctionBodies) {
   // Collect global stats on Decls/Stmts (until we have a module streamer).
   if (PrintStats) {
     Decl::EnableStatistics();
Index: lib/Frontend/ASTUnit.cpp
===================================================================
--- lib/Frontend/ASTUnit.cpp
+++ lib/Frontend/ASTUnit.cpp
@@ -1271,8 +1271,9 @@
 std::unique_ptr<llvm::MemoryBuffer>
 ASTUnit::getMainBufferWithPrecompiledPreamble(
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-    const CompilerInvocation &PreambleInvocationIn,
-    IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild,
+    CompilerInvocation &PreambleInvocationIn,
+    IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+    SkipFunctionBodiesOptions SkipFunctionBodiesOpts, bool AllowRebuild,
     unsigned MaxLines) {
   auto MainFilePath =
       PreambleInvocationIn.getFrontendOpts().Inputs[0].getFile();
@@ -1338,9 +1339,22 @@
     SimpleTimer PreambleTimer(WantTiming);
     PreambleTimer.setOutput("Precompiling preamble");
 
+    const SkipFunctionBodiesKind PreviousSkipFunctionBodies =
+        PreambleInvocationIn.getFrontendOpts().SkipFunctionBodies;
+    if (SkipFunctionBodiesOpts.Scope == SkipFunctionBodiesOptions::Preamble) {
+      PreambleInvocationIn.getFrontendOpts().SkipFunctionBodies =
+          SkipFunctionBodiesOpts.LimitToNonTemplateFunctions
+              ? SkipFunctionBodiesKind::AllExceptTemplates
+              : SkipFunctionBodiesKind::All;
+    }
+
     llvm::ErrorOr<PrecompiledPreamble> NewPreamble = PrecompiledPreamble::Build(
         PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS,
         PCHContainerOps, /*StoreInMemory=*/false, Callbacks);
+
+    PreambleInvocationIn.getFrontendOpts().SkipFunctionBodies =
+        PreviousSkipFunctionBodies;
+
     if (NewPreamble) {
       Preamble = std::move(*NewPreamble);
       PreambleRebuildCounter = 1;
@@ -1615,6 +1629,7 @@
 bool ASTUnit::LoadFromCompilerInvocation(
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
     unsigned PrecompilePreambleAfterNParses,
+    SkipFunctionBodiesOptions SkipFunctionBodiesOpts,
     IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
   if (!Invocation)
     return true;
@@ -1630,8 +1645,8 @@
   std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
   if (PrecompilePreambleAfterNParses > 0) {
     PreambleRebuildCounter = PrecompilePreambleAfterNParses;
-    OverrideMainBuffer =
-        getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
+    OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(
+        PCHContainerOps, *Invocation, VFS, SkipFunctionBodiesOpts);
     getDiagnostics().Reset();
     ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
   }
@@ -1678,6 +1693,7 @@
 
   if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
                                       PrecompilePreambleAfterNParses,
+                                      SkipFunctionBodiesOptions(),
                                       AST->FileMgr->getVirtualFileSystem()))
     return nullptr;
   return AST;
@@ -1691,8 +1707,9 @@
     ArrayRef<RemappedFile> RemappedFiles, bool RemappedFilesKeepOriginalName,
     unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
     bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
-    bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies,
-    bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization,
+    bool AllowPCHWithCompilerErrors,
+    SkipFunctionBodiesOptions SkipFunctionBodiesOpts, bool SingleFileParse,
+    bool UserFilesAreVolatile, bool ForSerialization,
     llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST,
     IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
   assert(Diags.get() && "no DiagnosticsEngine was provided");
@@ -1724,7 +1741,14 @@
   // Override the resources path.
   CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
 
-  CI->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodies;
+  if (SkipFunctionBodiesOpts.Scope == SkipFunctionBodiesOptions::MainFileAndPreamble) {
+    CI->getFrontendOpts().SkipFunctionBodies =
+        SkipFunctionBodiesOpts.LimitToNonTemplateFunctions
+            ? SkipFunctionBodiesKind::AllExceptTemplates
+            : SkipFunctionBodiesKind::All;
+  } else {
+    CI->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodiesKind::None;
+  }
 
   if (ModuleFormat)
     CI->getHeaderSearchOpts().ModuleFormat = ModuleFormat.getValue();
@@ -1762,6 +1786,7 @@
 
   if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
                                       PrecompilePreambleAfterNParses,
+                                      SkipFunctionBodiesOpts,
                                       VFS)) {
     // Some error occurred, if caller wants to examine diagnostics, pass it the
     // ASTUnit.
@@ -1777,6 +1802,7 @@
 
 bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
                       ArrayRef<RemappedFile> RemappedFiles,
+                      SkipFunctionBodiesOptions SkipFunBodiesOpts,
                       IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
   if (!Invocation)
     return true;
@@ -1806,8 +1832,8 @@
   // build a precompiled preamble, do so now.
   std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
   if (Preamble || PreambleRebuildCounter > 0)
-    OverrideMainBuffer =
-        getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
+    OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(
+        PCHContainerOps, *Invocation, VFS, SkipFunBodiesOpts);
 
   // Clear out the diagnostics state.
   FileMgr.reset();
@@ -2203,7 +2229,8 @@
         llvm::sys::fs::UniqueID MainID = MainStatus->getUniqueID();
         if (CompleteFileID == MainID && Line > 1)
           OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(
-              PCHContainerOps, Inv, VFS, false, Line - 1);
+              PCHContainerOps, Inv, VFS, SkipFunctionBodiesOptions(), false,
+              Line - 1);
       }
     }
   }
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -18,6 +18,7 @@
 #include "clang/Basic/OpenMPKinds.h"
 #include "clang/Basic/OperatorPrecedence.h"
 #include "clang/Basic/Specifiers.h"
+#include "clang/Frontend/SkipFunctionBodies.h"
 #include "clang/Lex/CodeCompletionHandler.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/DeclSpec.h"
@@ -261,15 +262,16 @@
   ///
   /// This option can be used, for example, to speed up searches for
   /// declarations/definitions when indexing.
-  bool SkipFunctionBodies;
+  SkipFunctionBodiesKind SkipFunctionBodies;
 
   /// The location of the expression statement that is being parsed right now.
   /// Used to determine if an expression that is being parsed is a statement or
   /// just a regular sub-expression.
   SourceLocation ExprStatementTokLoc;
 
 public:
-  Parser(Preprocessor &PP, Sema &Actions, bool SkipFunctionBodies);
+  Parser(Preprocessor &PP, Sema &Actions,
+         SkipFunctionBodiesKind SkipFunctionBodies);
   ~Parser() override;
 
   const LangOptions &getLangOpts() const { return PP.getLangOpts(); }
Index: include/clang/Parse/ParseAST.h
===================================================================
--- include/clang/Parse/ParseAST.h
+++ include/clang/Parse/ParseAST.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_PARSE_PARSEAST_H
 
 #include "clang/Basic/LangOptions.h"
+#include "clang/Frontend/SkipFunctionBodies.h"
 
 namespace clang {
   class Preprocessor;
@@ -36,16 +37,17 @@
   /// \param SkipFunctionBodies Whether to skip parsing of function bodies.
   /// This option can be used, for example, to speed up searches for
   /// declarations/definitions when indexing.
-  void ParseAST(Preprocessor &pp, ASTConsumer *C,
-                ASTContext &Ctx, bool PrintStats = false,
-                TranslationUnitKind TUKind = TU_Complete,
-                CodeCompleteConsumer *CompletionConsumer = nullptr,
-                bool SkipFunctionBodies = false);
+  void ParseAST(
+      Preprocessor &pp, ASTConsumer *C, ASTContext &Ctx,
+      bool PrintStats = false, TranslationUnitKind TUKind = TU_Complete,
+      CodeCompleteConsumer *CompletionConsumer = nullptr,
+      SkipFunctionBodiesKind SkipFunctionBodies = SkipFunctionBodiesKind::None);
 
   /// \brief Parse the main file known to the preprocessor, producing an 
   /// abstract syntax tree.
-  void ParseAST(Sema &S, bool PrintStats = false,
-                bool SkipFunctionBodies = false);
+  void ParseAST(
+      Sema &S, bool PrintStats = false,
+      SkipFunctionBodiesKind SkipFunctionBodies = SkipFunctionBodiesKind::None);
 
 }  // end namespace clang
 
Index: include/clang/Frontend/SkipFunctionBodies.h
===================================================================
--- /dev/null
+++ include/clang/Frontend/SkipFunctionBodies.h
@@ -0,0 +1,25 @@
+//===--- FrontendOptions.h --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_SKIPFUNCTIONBODIES_H
+#define LLVM_CLANG_FRONTEND_SKIPFUNCTIONBODIES_H
+
+namespace clang {
+
+/// Skip over function bodies to speed up parsing in cases you do not need
+/// them (e.g. with code completion).
+enum class SkipFunctionBodiesKind {
+  None,
+  All,
+  AllExceptTemplates,
+};
+
+} // end namespace clang
+
+#endif
Index: include/clang/Frontend/FrontendOptions.h
===================================================================
--- include/clang/Frontend/FrontendOptions.h
+++ include/clang/Frontend/FrontendOptions.h
@@ -11,6 +11,7 @@
 #define LLVM_CLANG_FRONTEND_FRONTENDOPTIONS_H
 
 #include "clang/Frontend/CommandLineSourceLoc.h"
+#include "clang/Frontend/SkipFunctionBodies.h"
 #include "clang/Serialization/ModuleFileExtension.h"
 #include "clang/Sema/CodeCompleteOptions.h"
 #include "llvm/ADT/StringRef.h"
@@ -274,10 +275,6 @@
   /// Emit ARC errors even if the migrator can fix them.
   unsigned ARCMTMigrateEmitARCErrors : 1;
 
-  /// Skip over function bodies to speed up parsing in cases you do not need
-  /// them (e.g. with code completion).
-  unsigned SkipFunctionBodies : 1;
-
   /// Whether we can use the global module index if available.
   unsigned UseGlobalModuleIndex : 1;
 
@@ -302,6 +299,8 @@
   /// Whether timestamps should be written to the produced PCH file.
   unsigned IncludeTimestamps : 1;
 
+  SkipFunctionBodiesKind SkipFunctionBodies;
+
   CodeCompleteOptions CodeCompleteOpts;
 
   enum {
@@ -444,10 +443,11 @@
         ShowStats(false), ShowTimers(false), ShowVersion(false),
         FixWhatYouCan(false), FixOnlyWarnings(false), FixAndRecompile(false),
         FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false),
-        SkipFunctionBodies(false), UseGlobalModuleIndex(true),
-        GenerateGlobalModuleIndex(true), ASTDumpDecls(false),
-        ASTDumpLookups(false), BuildingImplicitModule(false),
-        ModulesEmbedAllFiles(false), IncludeTimestamps(true) {}
+        UseGlobalModuleIndex(true), GenerateGlobalModuleIndex(true),
+        ASTDumpDecls(false), ASTDumpLookups(false),
+        BuildingImplicitModule(false), ModulesEmbedAllFiles(false),
+        IncludeTimestamps(true),
+        SkipFunctionBodies(SkipFunctionBodiesKind::None) {}
 
   /// getInputKindForExtension - Return the appropriate input kind for a file
   /// extension. For example, "c" would return InputKind::C.
Index: include/clang/Frontend/ASTUnit.h
===================================================================
--- include/clang/Frontend/ASTUnit.h
+++ include/clang/Frontend/ASTUnit.h
@@ -101,6 +101,12 @@
     std::vector<StandaloneFixIt> FixIts;
   };
 
+  struct SkipFunctionBodiesOptions {
+    SkipFunctionBodiesOptions() {}
+    enum { None, MainFileAndPreamble, Preamble } Scope = None;
+    bool LimitToNonTemplateFunctions = false;
+  };
+
 private:
   std::shared_ptr<LangOptions>            LangOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine>   Diagnostics;
@@ -363,9 +369,11 @@
 
   std::unique_ptr<llvm::MemoryBuffer> getMainBufferWithPrecompiledPreamble(
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-      const CompilerInvocation &PreambleInvocationIn,
-      IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild = true,
-      unsigned MaxLines = 0);
+      CompilerInvocation &PreambleInvocationIn,
+      IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+      SkipFunctionBodiesOptions SkipFunctionBodiesOpts =
+          SkipFunctionBodiesOptions(),
+      bool AllowRebuild = true, unsigned MaxLines = 0);
   void RealizeTopLevelDeclsFromPreamble();
 
   /// \brief Transfers ownership of the objects (like SourceManager) from
@@ -693,6 +701,7 @@
   bool LoadFromCompilerInvocation(
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
       unsigned PrecompilePreambleAfterNParses,
+      SkipFunctionBodiesOptions SkipFunctionBodiesOpts,
       IntrusiveRefCntPtr<vfs::FileSystem> VFS);
 
 public:
@@ -801,9 +810,11 @@
       TranslationUnitKind TUKind = TU_Complete,
       bool CacheCodeCompletionResults = false,
       bool IncludeBriefCommentsInCodeCompletion = false,
-      bool AllowPCHWithCompilerErrors = false, bool SkipFunctionBodies = false,
-      bool SingleFileParse = false,
-      bool UserFilesAreVolatile = false, bool ForSerialization = false,
+      bool AllowPCHWithCompilerErrors = false,
+      SkipFunctionBodiesOptions SkipFunctionBodiesOpts =
+          SkipFunctionBodiesOptions(),
+      bool SingleFileParse = false, bool UserFilesAreVolatile = false,
+      bool ForSerialization = false,
       llvm::Optional<StringRef> ModuleFormat = llvm::None,
       std::unique_ptr<ASTUnit> *ErrAST = nullptr,
       IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr);
@@ -821,6 +832,8 @@
   /// contain any translation-unit information, false otherwise.
   bool Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
                ArrayRef<RemappedFile> RemappedFiles = None,
+               SkipFunctionBodiesOptions SkipFunctionBodiesOpts =
+                   SkipFunctionBodiesOptions(),
                IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr);
 
   /// \brief Free data that will be re-generated on the next parse.
Index: include/clang-c/Index.h
===================================================================
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -1324,7 +1324,24 @@
   /**
    * \brief Sets the preprocessor in a mode for parsing a single file only.
    */
-  CXTranslationUnit_SingleFileParse = 0x400
+  CXTranslationUnit_SingleFileParse = 0x400,
+
+  /**
+   * \brief Used in combination with CXTranslationUnit_SkipFunctionBodies to
+   * constrain the skipping of function bodies to the preamble.
+   *
+   * The function bodies of the main file are not skipped.
+   */
+  CXTranslationUnit_LimitSkipFunctionBodiesToPreamble = 0x800,
+
+  /**
+   * \brief Used in combination with CXTranslationUnit_SkipFunctionBodies to
+   * exclude template function bodies from being skipped.
+   *
+   * Parsing template function bodies allows diagnostics for wrong/incomplete
+   * template instantiations.
+   */
+  CXTranslationUnit_LimitSkipFunctionBodiesToNonTemplates = 0x1000,
 };
 
 /**
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to