Skip to content

Commit 3841250

Browse files
authored
Merge pull request #30515 from rintaro/sourcekit-modulevalidation-rdar59567281
[SourceKit] Save clang module validation time
2 parents 88b093e + d0d1711 commit 3841250

File tree

21 files changed

+298
-1
lines changed

21 files changed

+298
-1
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import Foo
2+
3+
func test() {
4+
5+
}
6+
7+
// UNSUPPORTED: OS=windows-msvc
8+
9+
// -----------------------------------------------------------------------------
10+
// Test that modifications for frameworks in '-Fsystem' doesn't affect the result.
11+
12+
// RUN: %empty-directory(%t/ModuleCache)
13+
// RUN: %empty-directory(%t/System/Frameworks)
14+
// RUN: cp -R %S/../Inputs/build_session/Frameworks/Foo.framework %t/System/Frameworks/
15+
// RUN: cp -R %S/../Inputs/build_session/Frameworks/FooHelper.framework %t/System/Frameworks/
16+
// RUN: %sourcekitd-test \
17+
// RUN: -shell -- echo '## ONE' == \
18+
// RUN: -req=complete -pos=4:1 %s -- %s -D ONE -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache == \
19+
// RUN: -shell -- cp -R %S/../Inputs/build_session/Frameworks_modified/Foo.framework %t/System/Frameworks/ == \
20+
// RUN: -shell -- cp -R %S/../Inputs/build_session/Frameworks_modified/FooHelper.framework %t/System/Frameworks/ == \
21+
// RUN: -shell -- echo '## TWO' == \
22+
// RUN: -req=complete -pos=4:1 %s -- %s -D TWO -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache \
23+
// RUN: | tee %t.response | %FileCheck %s --check-prefix=CHECK_SYSTEM
24+
// RUN: sleep 2
25+
// RUN: %sourcekitd-test \
26+
// RUN: -shell -- echo '## THREE' == \
27+
// RUN: -req=complete -pos=4:1 %s -- %s -D TWO -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache \
28+
// RUN: | %FileCheck %s --check-prefix=CHECK_SYSTEM_2
29+
30+
// CHECK_SYSTEM-LABEL: ## ONE
31+
// CHECK_SYSTEM-DAG: key.description: "fooFunc(arg: Int32)"
32+
// CHECK_SYSTEM-DAG: key.description: "fooSubFunc(arg: Int32)"
33+
// CHECK_SYSTEM-DAG: key.description: "fooHelperFunc(arg: Int32)"
34+
// CHECK_SYSTEM-DAG: key.description: "fooHelperSubFunc(arg: Int32)"
35+
36+
// CHECK_SYSTEM-LABEL: ## TWO
37+
// CHECK_SYSTEM-DAG: key.description: "fooFunc(arg: Int32)"
38+
// CHECK_SYSTEM-DAG: key.description: "fooSubFunc(arg: Int32)"
39+
// CHECK_SYSTEM-DAG: key.description: "fooHelperFunc(arg: Int32)"
40+
// CHECK_SYSTEM-DAG: key.description: "fooHelperSubFunc(arg: Int32)"
41+
42+
// CHECK_SYSTEM_2-LABEL: ## THREE
43+
// CHECK_SYSTEM_2-NOT: fooFunc(
44+
// CHECK_SYSTEM_2-NOT: fooSubFunc(
45+
// CHECK_SYSTEM_2-NOT: fooHelperFunc(
46+
// CHECK_SYSTEM_2-NOT: fooHelperSubFunc(
47+
// CHECK_SYSTEM_2-DAG: key.description: "fooFunc_mod(arg: Int32)"
48+
// CHECK_SYSTEM_2-DAG: key.description: "fooSubFunc_mod(arg: Int32)"
49+
// CHECK_SYSTEM_2-DAG: key.description: "fooHelperFunc_mod(arg: Int32)"
50+
// CHECK_SYSTEM_2-DAG: key.description: "fooHelperSubFunc_mod(arg: Int32)"
51+
// CHECK_SYSTEM_2-NOT: fooFunc(
52+
// CHECK_SYSTEM_2-NOT: fooSubFunc(
53+
// CHECK_SYSTEM_2-NOT: fooHelperFunc(
54+
// CHECK_SYSTEM_2-NOT: fooHelperSubFunc(
55+
56+
// -----------------------------------------------------------------------------
57+
// Test that modifications for frameworks in '-F' are immidiately propagated
58+
// while modifications for frameworks in '-Fsystem' are not.
59+
60+
// RUN: %empty-directory(%t/ModuleCache)
61+
// RUN: %empty-directory(%t/Frameworks)
62+
// RUN: %empty-directory(%t/System/Frameworks)
63+
// RUN: cp -R %S/../Inputs/build_session/Frameworks/Foo.framework %t/Frameworks/
64+
// RUN: cp -R %S/../Inputs/build_session/Frameworks/FooHelper.framework %t/System/Frameworks/
65+
// RUN: %sourcekitd-test \
66+
// RUN: -shell -- echo '## ONE' == \
67+
// RUN: -req=complete -pos=4:1 %s -- %s -D ONE -F %t/Frameworks -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache == \
68+
// RUN: -shell -- cp -R %S/../Inputs/build_session/Frameworks_modified/Foo.framework %t/Frameworks/ == \
69+
// RUN: -shell -- cp -R %S/../Inputs/build_session/Frameworks_modified/FooHelper.framework %t/System/Frameworks/ == \
70+
// RUN: -shell -- echo '## TWO' == \
71+
// RUN: -req=complete -pos=4:1 %s -- %s -D TWO -F %t/Frameworks -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache \
72+
// RUN: | %FileCheck %s --check-prefix=CHECK_USER
73+
74+
// CHECK_USER-LABEL: ## ONE
75+
// CHECK_USER-DAG: key.description: "fooFunc(arg: Int32)"
76+
// CHECK_USER-DAG: key.description: "fooSubFunc(arg: Int32)"
77+
// CHECK_USER-DAG: key.description: "fooHelperFunc(arg: Int32)"
78+
// CHECK_USER-DAG: key.description: "fooHelperSubFunc(arg: Int32)"
79+
80+
// CHECK_USER-LABEL: ## TWO
81+
// CHECK_USER-NOT: fooFunc(
82+
// CHECK_USER-NOT: fooSubFunc(
83+
// CHECK_USER-DAG: key.description: "fooFunc_mod(arg: Int32)"
84+
// CHECK_USER-DAG: key.description: "fooSubFunc_mod(arg: Int32)"
85+
// CHECK_USER-DAG: key.description: "fooHelperFunc(arg: Int32)"
86+
// CHECK_USER-DAG: key.description: "fooHelperSubFunc(arg: Int32)"
87+
// CHECK_USER-NOT: fooFunc(
88+
// CHECK_USER-NOT: fooSubFunc(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#if !defined(__FOOSUB_H__)
2+
#define __FOOSUB_H__ 1
3+
4+
int fooSubFunc(int arg);
5+
6+
#endif /* ! __FOOSUB_H__ */
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* Foo.h
2+
Copyright (c) 1815, Napoleon Bonaparte. All rights reserved.
3+
*/
4+
#if !defined(__FOO_H__)
5+
#define __FOO_H__ 1
6+
7+
#import <FooSub/FooSub.h>
8+
#import <FooHelper/FooHelper.h>
9+
10+
int fooFunc(int arg);
11+
12+
#endif /* ! __FOO_H__ */
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
framework module Foo {
2+
umbrella header "Foo.h"
3+
export *
4+
framework module FooSub {
5+
umbrella header "FooSub.h"
6+
export *
7+
}
8+
}
9+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int fooHelperSubFunc(int arg);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#import <FooHelperSub/FooHelperSub.h>
2+
3+
int fooHelperFunc(int arg);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int fooHelperExplicitFunc(int a);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
framework module FooHelper {
2+
umbrella header "FooHelper.h"
3+
4+
framework module FooHelperSub {
5+
umbrella header "FooHelperSub.h"
6+
}
7+
8+
explicit module FooHelperExplicit {
9+
header "FooHelperExplicit.h"
10+
}
11+
}
12+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#if !defined(__FOOSUB_H__)
2+
#define __FOOSUB_H__ 1
3+
4+
int fooSubFunc_mod(int arg);
5+
6+
#endif /* ! __FOOSUB_H__ */
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* Foo.h
2+
Copyright (c) 1815, Napoleon Bonaparte. All rights reserved.
3+
*/
4+
#if !defined(__FOO_H__)
5+
#define __FOO_H__ 1
6+
7+
#import <FooSub/FooSub.h>
8+
#import <FooHelper/FooHelper.h>
9+
10+
int fooFunc_mod(int arg);
11+
12+
#endif /* ! __FOO_H__ */
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
framework module Foo {
2+
umbrella header "Foo.h"
3+
export *
4+
framework module FooSub {
5+
umbrella header "FooSub.h"
6+
export *
7+
}
8+
}
9+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int fooHelperSubFunc_mod(int arg);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#import <FooHelperSub/FooHelperSub.h>
2+
3+
int fooHelperFunc_mod(int arg);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int fooHelperExplicitFunc_mod(int a);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
framework module FooHelper {
2+
umbrella header "FooHelper.h"
3+
4+
framework module FooHelperSub {
5+
umbrella header "FooHelperSub.h"
6+
}
7+
8+
explicit module FooHelperExplicit {
9+
header "FooHelperExplicit.h"
10+
}
11+
}
12+
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import Foo
2+
import FooHelper.FooHelperExplicit
3+
4+
func swiftFunc() -> Int { 1 }
5+
6+
func test() {
7+
_ = fooFunc(1)
8+
_ = fooSubFunc(1)
9+
_ = fooHelperFunc(1)
10+
_ = fooHelperSubFunc(1)
11+
_ = fooHelperExplicitFunc(1)
12+
_ = swiftFunc()
13+
}
14+
15+
// UNSUPPORTED: OS=windows-msvc
16+
17+
// -----------------------------------------------------------------------------
18+
// Test that modifications for frameworks in '-Fsystem' doesn't affect the result.
19+
20+
// RUN: %empty-directory(%t/ModuleCache)
21+
// RUN: %empty-directory(%t/System/Frameworks)
22+
// RUN: cp -R %S/../Inputs/build_session/Frameworks/Foo.framework %t/System/Frameworks/
23+
// RUN: cp -R %S/../Inputs/build_session/Frameworks/FooHelper.framework %t/System/Frameworks/
24+
// RUN: %sourcekitd-test \
25+
// RUN: -shell -- echo '## ONE' == \
26+
// RUN: -req=sema %s -- %s -D ONE -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache == \
27+
// RUN: -shell -- cp -R %S/../Inputs/build_session/Frameworks_modified/Foo.framework %t/System/Frameworks/ == \
28+
// RUN: -shell -- cp -R %S/../Inputs/build_session/Frameworks_modified/FooHelper.framework %t/System/Frameworks/ == \
29+
// RUN: -shell -- echo '## TWO' == \
30+
// RUN: -req=sema %s -- %s -D TWO -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache \
31+
// RUN: | %FileCheck %s --check-prefix=CHECK_SYSTEM
32+
// RUN: sleep 2
33+
// RUN: %sourcekitd-test \
34+
// RUN: -shell -- echo '## THREE' == \
35+
// RUN: -req=sema %s -- %s -D THREE -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache \
36+
// RUN: | %FileCheck %s --check-prefix=CHECK_SYSTEM_2
37+
38+
// CHECK_SYSTEM-LABEL: ## ONE
39+
// CHECK_SYSTEM-NOT: key.description
40+
41+
// CHECK_SYSTEM-LABEL: ## TWO
42+
// CHECK_SYSTEM-NOT: key.description
43+
44+
// CHECK_SYSTEM_2-LABEL: ## THREE
45+
// CHECK_SYSTEM_2: key.severity: source.diagnostic.severity.error,
46+
// CHECK_SYSTEM_2-NEXT: key.description: "use of unresolved identifier 'fooFunc'",
47+
// CHECK_SYSTEM_2: key.severity: source.diagnostic.severity.error,
48+
// CHECK_SYSTEM_2-NEXT: key.description: "use of unresolved identifier 'fooSubFunc'",
49+
// CHECK_SYSTEM_2: key.severity: source.diagnostic.severity.error,
50+
// CHECK_SYSTEM_2-NEXT: key.description: "use of unresolved identifier 'fooHelperFunc'",
51+
// CHECK_SYSTEM_2: key.severity: source.diagnostic.severity.error,
52+
// CHECK_SYSTEM_2-NEXT: key.description: "use of unresolved identifier 'fooHelperSubFunc'",
53+
// CHECK_SYSTEM_2: key.severity: source.diagnostic.severity.error,
54+
// CHECK_SYSTEM_2-NEXT: key.description: "use of unresolved identifier 'fooHelperExplicitFunc'",
55+
56+
// -----------------------------------------------------------------------------
57+
// Test that modifications for frameworks in '-F' are immidiately propagated
58+
// while modifications for frameworks in '-Fsystem' are not.
59+
60+
// RUN: %empty-directory(%t/ModuleCache)
61+
// RUN: %empty-directory(%t/Frameworks)
62+
// RUN: %empty-directory(%t/System/Frameworks)
63+
// RUN: cp -R %S/../Inputs/build_session/Frameworks/Foo.framework %t/Frameworks/
64+
// RUN: cp -R %S/../Inputs/build_session/Frameworks/FooHelper.framework %t/System/Frameworks/
65+
// RUN: %sourcekitd-test \
66+
// RUN: -shell -- echo '## ONE' == \
67+
// RUN: -req=sema %s -- %s -D ONE -F %t/Frameworks -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache == \
68+
// RUN: -shell -- cp -R %S/../Inputs/build_session/Frameworks_modified/Foo.framework %t/Frameworks/ == \
69+
// RUN: -shell -- cp -R %S/../Inputs/build_session/Frameworks_modified/FooHelper.framework %t/System/Frameworks/ == \
70+
// RUN: -shell -- echo '## TWO' == \
71+
// RUN: -req=sema %s -- %s -D TWO -F %t/Frameworks -Fsystem %t/System/Frameworks -module-cache-path %t/ModuleCache \
72+
// RUN: | tee %t.reponse | %FileCheck %s --check-prefix=CHECK_USER
73+
74+
// CHECK_USER-LABEL: ## ONE
75+
// CHECK_USER-NOT: key.description
76+
77+
// CHECK_USER-LABEL: ## TWO
78+
// CHECK_USER-NOT: key.severity:
79+
// CHECK_USER: key.severity: source.diagnostic.severity.error,
80+
// CHECK_USER-NEXT: key.description: "use of unresolved identifier 'fooFunc'",
81+
// CHECK_USER: key.severity: source.diagnostic.severity.error,
82+
// CHECK_USER-NEXT: key.description: "use of unresolved identifier 'fooSubFunc'",
83+
// CHECK_USER-NOT: key.severity:

tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "swift/Sema/IDETypeChecking.h"
3232

3333
#include "llvm/ADT/FoldingSet.h"
34+
#include "llvm/Support/Chrono.h"
3435
#include "llvm/Support/FileSystem.h"
3536
#include "llvm/Support/MemoryBuffer.h"
3637
#include "llvm/Support/Path.h"
@@ -374,7 +375,9 @@ struct SwiftASTManager::Implementation {
374375
std::shared_ptr<GlobalConfig> Config,
375376
std::shared_ptr<SwiftStatistics> Stats, StringRef RuntimeResourcePath)
376377
: EditorDocs(EditorDocs), Config(Config), Stats(Stats),
377-
RuntimeResourcePath(RuntimeResourcePath) {}
378+
RuntimeResourcePath(RuntimeResourcePath),
379+
SessionTimestamp(llvm::sys::toTimeT(std::chrono::system_clock::now())) {
380+
}
378381

379382
std::shared_ptr<SwiftEditorDocumentFileMap> EditorDocs;
380383
std::shared_ptr<GlobalConfig> Config;
@@ -383,6 +386,7 @@ struct SwiftASTManager::Implementation {
383386
SourceManager SourceMgr;
384387
Cache<ASTKey, ASTProducerRef> ASTCache{ "sourcekit.swift.ASTCache" };
385388
llvm::sys::Mutex CacheMtx;
389+
std::time_t SessionTimestamp;
386390

387391
WorkQueue ASTBuildQueue{ WorkQueue::Dequeuing::Serial,
388392
"sourcekit.swift.ASTBuilding" };
@@ -548,6 +552,18 @@ bool SwiftASTManager::initCompilerInvocation(
548552
if (Impl.Config->shouldOptimizeForIDE())
549553
FrontendOpts.IgnoreSwiftSourceInfo = true;
550554

555+
// To save the time for module validation, consider the lifetime of ASTManager
556+
// as a single build session.
557+
// NOTE: 'SessionTimestamp - 1' because clang compares it with '<=' that may
558+
// cause unnecessary validations if they happens within one second from
559+
// the SourceKit startup.
560+
ImporterOpts.ExtraArgs.push_back("-fbuild-session-timestamp=" +
561+
std::to_string(Impl.SessionTimestamp - 1));
562+
ImporterOpts.ExtraArgs.push_back("-fmodules-validate-once-per-build-session");
563+
564+
auto &SearchPathOpts = Invocation.getSearchPathOptions();
565+
SearchPathOpts.DisableModulesValidateSystemDependencies = true;
566+
551567
// Disable expensive SIL options to reduce time spent in SILGen.
552568
disableExpensiveSILOptions(Invocation.getSILOptions());
553569

tools/SourceKit/tools/sourcekitd-test/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ def suppress_config_request : Flag<["-"], "suppress-config-request">,
149149
def module_cache_path: Separate<["-"], "module-cache-path">, HelpText<"module cache path">;
150150
def module_cache_path_EQ : Joined<["-"], "module-cache-path=">, Alias<module_cache_path>;
151151

152+
def shell: Flag<["-"], "shell">,
153+
HelpText<"Run shell command">;
154+
152155
def help : Flag<["-", "--"], "help">,
153156
HelpText<"Display available options">;
154157

tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,10 @@ bool TestOptions::parseArgs(llvm::ArrayRef<const char *> Args) {
389389
ModuleCachePath = InputArg->getValue();
390390
break;
391391

392+
case OPT_shell:
393+
ShellExecution = true;
394+
break;
395+
392396
case OPT_UNKNOWN:
393397
llvm::errs() << "error: unknown argument: "
394398
<< InputArg->getAsString(ParsedArgs) << '\n'

tools/SourceKit/tools/sourcekitd-test/TestOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ struct TestOptions {
124124
llvm::StringMap<VFSFile> VFSFiles;
125125
llvm::Optional<std::string> VFSName;
126126
llvm::Optional<bool> CancelOnSubsequentRequest;
127+
bool ShellExecution = false;
127128
bool parseArgs(llvm::ArrayRef<const char *> Args);
128129
void printHelp(bool ShowHidden) const;
129130
};

tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "llvm/Support/FormatVariadic.h"
2727
#include "llvm/Support/MemoryBuffer.h"
2828
#include "llvm/Support/Path.h"
29+
#include "llvm/Support/Program.h"
2930
#include "llvm/Support/Regex.h"
3031
#include "llvm/Support/Signals.h"
3132
#include "llvm/Support/Threading.h"
@@ -387,6 +388,16 @@ static int handleJsonRequestPath(StringRef QueryPath, const TestOptions &Opts) {
387388
return Error ? 1 : 0;
388389
}
389390

391+
static int performShellExecution(ArrayRef<const char *> Args) {
392+
auto Program = llvm::sys::findProgramByName(Args[0]);
393+
if (std::error_code ec = Program.getError()) {
394+
llvm::errs() << "command not found: " << Args[0] << "\n";
395+
return ec.value();
396+
}
397+
SmallVector<StringRef, 8> execArgs(Args.begin(), Args.end());
398+
return llvm::sys::ExecuteAndWait(*Program, execArgs);
399+
}
400+
390401
static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts);
391402

392403
static int handleTestInvocation(ArrayRef<const char *> Args,
@@ -419,6 +430,9 @@ static int handleTestInvocation(ArrayRef<const char *> Args,
419430
}
420431
}
421432

433+
if (Opts.ShellExecution)
434+
return performShellExecution(Opts.CompilerArgs);
435+
422436
assert(Opts.repeatRequest >= 1);
423437
for (unsigned i = 0; i < Opts.repeatRequest; ++i) {
424438
if (int ret = handleTestInvocation(Opts, InitOpts)) {

0 commit comments

Comments
 (0)