Skip to content

Commit f1a4f69

Browse files
Report project reference diagnostics (#1515)
Co-authored-by: Copilot <[email protected]>
1 parent a149911 commit f1a4f69

File tree

89 files changed

+101
-1065
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+101
-1065
lines changed

internal/compiler/emitHost.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,7 @@ func (host *emitHost) UseCaseSensitiveFileNames() bool {
108108
}
109109

110110
func (host *emitHost) IsEmitBlocked(file string) bool {
111-
// !!!
112-
return false
111+
return host.program.IsEmitBlocked(file)
113112
}
114113

115114
func (host *emitHost) WriteFile(fileName string, text string, writeByteOrderMark bool) error {

internal/compiler/program.go

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ func (p *Program) GetParseFileRedirect(fileName string) string {
128128
}
129129

130130
func (p *Program) ForEachResolvedProjectReference(
131-
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine),
131+
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int),
132132
) {
133133
p.projectReferenceFileMapper.forEachResolvedProjectReference(fn)
134134
}
@@ -544,9 +544,7 @@ func (p *Program) verifyCompilerOptions() {
544544
}
545545
}
546546

547-
// !!! Option_incremental_can_only_be_specified_using_tsconfig_emitting_to_single_file_or_when_option_tsBuildInfoFile_is_specified
548-
549-
// !!! verifyProjectReferences
547+
p.verifyProjectReferences()
550548

551549
if options.Composite.IsTrue() {
552550
var rootPaths collections.Set[tspath.Path]
@@ -810,12 +808,13 @@ func (p *Program) verifyCompilerOptions() {
810808
}
811809

812810
outputpaths.ForEachEmittedFile(p, options, func(emitFileNames *outputpaths.OutputPaths, sourceFile *ast.SourceFile) bool {
813-
if !options.EmitDeclarationOnly.IsTrue() {
814-
verifyEmitFilePath(emitFileNames.JsFilePath())
815-
}
811+
verifyEmitFilePath(emitFileNames.JsFilePath())
812+
verifyEmitFilePath(emitFileNames.SourceMapFilePath())
816813
verifyEmitFilePath(emitFileNames.DeclarationFilePath())
814+
verifyEmitFilePath(emitFileNames.DeclarationMapPath())
817815
return false
818816
}, p.getSourceFilesToEmit(nil, false), false)
817+
verifyEmitFilePath(p.opts.Config.GetBuildInfoFileName())
819818
}
820819
}
821820

@@ -824,6 +823,58 @@ func (p *Program) blockEmittingOfFile(emitFileName string, diag *ast.Diagnostic)
824823
p.programDiagnostics = append(p.programDiagnostics, diag)
825824
}
826825

826+
func (p *Program) IsEmitBlocked(emitFileName string) bool {
827+
return p.hasEmitBlockingDiagnostics.Has(p.toPath(emitFileName))
828+
}
829+
830+
func (p *Program) verifyProjectReferences() {
831+
buildInfoFileName := core.IfElse(!p.Options().SuppressOutputPathCheck.IsTrue(), p.opts.Config.GetBuildInfoFileName(), "")
832+
createDiagnosticForReference := func(config *tsoptions.ParsedCommandLine, index int, message *diagnostics.Message, args ...any) {
833+
var sourceFile *ast.SourceFile
834+
if config.ConfigFile != nil {
835+
sourceFile = config.ConfigFile.SourceFile
836+
}
837+
diag := tsoptions.ForEachTsConfigPropArray(sourceFile, "references", func(property *ast.PropertyAssignment) *ast.Diagnostic {
838+
if ast.IsArrayLiteralExpression(property.Initializer) {
839+
value := property.Initializer.AsArrayLiteralExpression().Elements.Nodes
840+
if len(value) > index {
841+
return tsoptions.CreateDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, value[index], message, args...)
842+
}
843+
}
844+
return nil
845+
})
846+
if diag == nil {
847+
diag = ast.NewCompilerDiagnostic(message, args...)
848+
}
849+
p.programDiagnostics = append(p.programDiagnostics, diag)
850+
}
851+
852+
p.ForEachResolvedProjectReference(func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int) {
853+
ref := parent.ProjectReferences()[index]
854+
// !!! Deprecated in 5.0 and removed since 5.5
855+
// verifyRemovedProjectReference(ref, parent, index);
856+
if config == nil {
857+
createDiagnosticForReference(parent, index, diagnostics.File_0_not_found, ref.Path)
858+
return
859+
}
860+
refOptions := config.CompilerOptions()
861+
if !refOptions.Composite.IsTrue() || refOptions.NoEmit.IsTrue() {
862+
if len(config.FileNames()) > 0 {
863+
if !refOptions.Composite.IsTrue() {
864+
createDiagnosticForReference(parent, index, diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.Path)
865+
}
866+
if refOptions.NoEmit.IsTrue() {
867+
createDiagnosticForReference(parent, index, diagnostics.Referenced_project_0_may_not_disable_emit, ref.Path)
868+
}
869+
}
870+
}
871+
if buildInfoFileName != "" && buildInfoFileName == config.GetBuildInfoFileName() {
872+
createDiagnosticForReference(parent, index, diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoFileName, ref.Path)
873+
p.hasEmitBlockingDiagnostics.Add(p.toPath(buildInfoFileName))
874+
}
875+
})
876+
}
877+
827878
func hasZeroOrOneAsteriskCharacter(str string) bool {
828879
seenAsterisk := false
829880
for _, ch := range str {

internal/compiler/projectreferencefilemapper.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,23 +140,30 @@ func (mapper *projectReferenceFileMapper) getResolvedReferenceFor(path tspath.Pa
140140
}
141141

142142
func (mapper *projectReferenceFileMapper) forEachResolvedProjectReference(
143-
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine),
143+
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int),
144144
) {
145145
if mapper.opts.Config.ConfigFile == nil {
146146
return
147147
}
148+
seenRef := collections.NewSetWithSizeHint[tspath.Path](len(mapper.referencesInConfigFile))
149+
seenRef.Add(mapper.opts.Config.ConfigFile.SourceFile.Path())
148150
refs := mapper.referencesInConfigFile[mapper.opts.Config.ConfigFile.SourceFile.Path()]
149-
mapper.forEachResolvedReferenceWorker(refs, fn)
151+
mapper.forEachResolvedReferenceWorker(refs, fn, mapper.opts.Config, seenRef)
150152
}
151153

152154
func (mapper *projectReferenceFileMapper) forEachResolvedReferenceWorker(
153155
references []tspath.Path,
154-
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine),
156+
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int),
157+
parent *tsoptions.ParsedCommandLine,
158+
seenRef *collections.Set[tspath.Path],
155159
) {
156-
for _, path := range references {
160+
for index, path := range references {
161+
if !seenRef.AddIfAbsent(path) {
162+
continue
163+
}
157164
config, _ := mapper.configToProjectReference[path]
158-
fn(path, config)
159-
mapper.forEachResolvedReferenceWorker(mapper.referencesInConfigFile[path], fn)
165+
fn(path, config, parent, index)
166+
mapper.forEachResolvedReferenceWorker(mapper.referencesInConfigFile[path], fn, config, seenRef)
160167
}
161168
}
162169

internal/execute/tscprojectreferences_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
func TestProjectReferences(t *testing.T) {
1010
t.Parallel()
1111
cases := []tscInput{
12-
// !!! sheetal todo verifyCompilerOptions - check for noEmit
1312
{
1413
subScenario: "when project references composite project with noEmit",
1514
files: FileMap{
@@ -76,7 +75,6 @@ func TestProjectReferences(t *testing.T) {
7675
commandLineArgs: []string{"--p", "project"},
7776
},
7877
{
79-
// !!! sheetal verifyProjectReferences - checks this
8078
subScenario: "when project contains invalid project reference",
8179
files: FileMap{
8280
"/home/src/workspaces/solution/project/index.ts": `export const x = 10;`,

internal/incremental/incremental.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ package incremental
33
import (
44
"github.com/go-json-experiment/json"
55
"github.com/microsoft/typescript-go/internal/compiler"
6-
"github.com/microsoft/typescript-go/internal/outputpaths"
76
"github.com/microsoft/typescript-go/internal/tsoptions"
8-
"github.com/microsoft/typescript-go/internal/tspath"
97
)
108

119
type BuildInfoReader interface {
@@ -39,10 +37,7 @@ func NewBuildInfoReader(
3937
}
4038

4139
func ReadBuildInfoProgram(config *tsoptions.ParsedCommandLine, reader BuildInfoReader) *Program {
42-
buildInfoFileName := outputpaths.GetBuildInfoFileName(config.CompilerOptions(), tspath.ComparePathsOptions{
43-
CurrentDirectory: config.GetCurrentDirectory(),
44-
UseCaseSensitiveFileNames: config.UseCaseSensitiveFileNames(),
45-
})
40+
buildInfoFileName := config.GetBuildInfoFileName()
4641
if buildInfoFileName == "" {
4742
return nil
4843
}

internal/incremental/program.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ func (p *Program) emitBuildInfo(ctx context.Context, options compiler.EmitOption
240240
CurrentDirectory: p.program.GetCurrentDirectory(),
241241
UseCaseSensitiveFileNames: p.program.UseCaseSensitiveFileNames(),
242242
})
243-
if buildInfoFileName == "" {
243+
if buildInfoFileName == "" || p.program.IsEmitBlocked(buildInfoFileName) {
244244
return nil
245245
}
246246
if p.snapshot.hasErrors == core.TSUnknown {

internal/project/project.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ func (p *Project) updateGraph() (*compiler.Program, bool) {
533533
}
534534
}
535535

536-
oldProgram.ForEachResolvedProjectReference(func(path tspath.Path, ref *tsoptions.ParsedCommandLine) {
536+
oldProgram.ForEachResolvedProjectReference(func(path tspath.Path, ref *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int) {
537537
if _, ok := p.program.GetResolvedProjectReferenceFor(path); !ok {
538538
p.host.ConfigFileRegistry().releaseConfig(path, p)
539539
}
@@ -1096,7 +1096,7 @@ func (p *Project) Close() {
10961096
// Detach script info if its not root or is root of non inferred project
10971097
p.detachScriptInfoIfNotInferredRoot(sourceFile.Path())
10981098
}
1099-
p.program.ForEachResolvedProjectReference(func(path tspath.Path, ref *tsoptions.ParsedCommandLine) {
1099+
p.program.ForEachResolvedProjectReference(func(path tspath.Path, ref *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int) {
11001100
p.host.ConfigFileRegistry().releaseConfig(path, p)
11011101
})
11021102
if p.kind == KindConfigured {

internal/tsoptions/parsedcommandline.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ func (p *ParsedCommandLine) CompilerOptions() *core.CompilerOptions {
179179
return p.ParsedConfig.CompilerOptions
180180
}
181181

182+
func (p *ParsedCommandLine) GetBuildInfoFileName() string {
183+
return outputpaths.GetBuildInfoFileName(p.CompilerOptions(), p.comparePathsOptions)
184+
}
185+
182186
func (p *ParsedCommandLine) SetTypeAcquisition(o *core.TypeAcquisition) {
183187
p.ParsedConfig.TypeAcquisition = o
184188
}

testdata/baselines/reference/compiler/superCallInJSWithWrongBaseTypeArgumentCount1(strict=false).js

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,29 +31,6 @@ exports.A = void 0;
3131
class A {
3232
}
3333
exports.A = A;
34-
//// [b.js]
35-
"use strict";
36-
Object.defineProperty(exports, "__esModule", { value: true });
37-
exports.B3 = exports.B2 = exports.B1 = void 0;
38-
const a_js_1 = require("./a.js");
39-
class B1 extends a_js_1.A {
40-
constructor() {
41-
super();
42-
}
43-
}
44-
exports.B1 = B1;
45-
class B2 extends a_js_1.A {
46-
constructor() {
47-
super();
48-
}
49-
}
50-
exports.B2 = B2;
51-
class B3 extends a_js_1.A {
52-
constructor() {
53-
super();
54-
}
55-
}
56-
exports.B3 = B3;
5734

5835

5936
//// [a.d.ts]

testdata/baselines/reference/compiler/superCallInJSWithWrongBaseTypeArgumentCount1(strict=true).js

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,29 +31,6 @@ exports.A = void 0;
3131
class A {
3232
}
3333
exports.A = A;
34-
//// [b.js]
35-
"use strict";
36-
Object.defineProperty(exports, "__esModule", { value: true });
37-
exports.B3 = exports.B2 = exports.B1 = void 0;
38-
const a_js_1 = require("./a.js");
39-
class B1 extends a_js_1.A {
40-
constructor() {
41-
super();
42-
}
43-
}
44-
exports.B1 = B1;
45-
class B2 extends a_js_1.A {
46-
constructor() {
47-
super();
48-
}
49-
}
50-
exports.B2 = B2;
51-
class B3 extends a_js_1.A {
52-
constructor() {
53-
super();
54-
}
55-
}
56-
exports.B3 = B3;
5734

5835

5936
//// [a.d.ts]

0 commit comments

Comments
 (0)