Skip to content

Commit bb48727

Browse files
committed
Merge branch 'master' into projzilla
2 parents 47d34cb + d8f6f30 commit bb48727

File tree

9 files changed

+772
-24
lines changed

9 files changed

+772
-24
lines changed

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,29 +61,29 @@ Change to the TypeScript directory:
6161
cd TypeScript
6262
```
6363

64-
Install Gulp tools and dev dependencies:
64+
Install Jake tools and dev dependencies:
6565

6666
```bash
67-
npm install -g gulp
67+
npm install -g jake
6868
npm install
6969
```
7070

7171
Use one of the following to build and test:
7272

7373
```
74-
gulp local # Build the compiler into built/local
75-
gulp clean # Delete the built compiler
76-
gulp LKG # Replace the last known good with the built one.
74+
jake local # Build the compiler into built/local
75+
jake clean # Delete the built compiler
76+
jake LKG # Replace the last known good with the built one.
7777
# Bootstrapping step to be executed when the built compiler reaches a stable state.
78-
gulp tests # Build the test infrastructure using the built compiler.
79-
gulp runtests # Run tests using the built compiler and test infrastructure.
78+
jake tests # Build the test infrastructure using the built compiler.
79+
jake runtests # Run tests using the built compiler and test infrastructure.
8080
# You can override the host or specify a test for this command.
8181
# Use host=<hostName> or tests=<testPath>.
82-
gulp runtests-browser # Runs the tests using the built run.js file. Syntax is gulp runtests. Optional
82+
jake runtests-browser # Runs the tests using the built run.js file. Syntax is jake runtests. Optional
8383
parameters 'host=', 'tests=[regex], reporter=[list|spec|json|<more>]'.
84-
gulp baseline-accept # This replaces the baseline test results with the results obtained from gulp runtests.
85-
gulp lint # Runs tslint on the TypeScript source.
86-
gulp help # List the above commands.
84+
jake baseline-accept # This replaces the baseline test results with the results obtained from jake runtests.
85+
jake lint # Runs tslint on the TypeScript source.
86+
jake help # List the above commands.
8787
```
8888

8989

src/compiler/checker.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17122,20 +17122,28 @@ namespace ts {
1712217122

1712317123
// Find the first enclosing class that has the declaring classes of the protected constituents
1712417124
// of the property as base classes
17125-
const enclosingClass = forEachEnclosingClass(node, enclosingDeclaration => {
17125+
let enclosingClass = forEachEnclosingClass(node, enclosingDeclaration => {
1712617126
const enclosingClass = <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingDeclaration)!);
1712717127
return isClassDerivedFromDeclaringClasses(enclosingClass, prop) ? enclosingClass : undefined;
1712817128
});
1712917129
// A protected property is accessible if the property is within the declaring class or classes derived from it
1713017130
if (!enclosingClass) {
17131-
error(errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, symbolToString(prop), typeToString(getDeclaringClass(prop) || type));
17132-
return false;
17131+
// allow PropertyAccessibility if context is in function with this parameter
17132+
// static member access is disallow
17133+
let thisParameter: ParameterDeclaration | undefined;
17134+
if (flags & ModifierFlags.Static || !(thisParameter = getThisParameterFromNodeContext(node)) || !thisParameter.type) {
17135+
error(errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, symbolToString(prop), typeToString(getDeclaringClass(prop) || type));
17136+
return false;
17137+
}
17138+
17139+
const thisType = getTypeFromTypeNode(thisParameter.type);
17140+
enclosingClass = ((thisType.flags & TypeFlags.TypeParameter) ? getConstraintFromTypeParameter(<TypeParameter>thisType) : thisType) as InterfaceType;
1713317141
}
1713417142
// No further restrictions for static properties
1713517143
if (flags & ModifierFlags.Static) {
1713617144
return true;
1713717145
}
17138-
if (type.flags & TypeFlags.TypeParameter) {
17146+
if (type.flags & TypeFlags.TypeParameter) {
1713917147
// get the original type -- represented as the type constraint of the 'this' type
1714017148
type = (type as TypeParameter).isThisType ? getConstraintOfTypeParameter(<TypeParameter>type)! : getBaseConstraintOfType(<TypeParameter>type)!; // TODO: GH#18217 Use a different variable that's allowed to be undefined
1714117149
}
@@ -17146,6 +17154,11 @@ namespace ts {
1714617154
return true;
1714717155
}
1714817156

17157+
function getThisParameterFromNodeContext (node: Node) {
17158+
const thisContainer = getThisContainer(node, /* includeArrowFunctions */ false);
17159+
return thisContainer && isFunctionLike(thisContainer) ? getThisParameter(thisContainer) : undefined;
17160+
}
17161+
1714917162
function symbolHasNonMethodDeclaration(symbol: Symbol) {
1715017163
return forEachProperty(symbol, prop => {
1715117164
const propKind = getDeclarationKindFromSymbol(prop);

src/server/session.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,8 @@ namespace ts.server {
511511

512512
const { fileName, project } = checkList[index];
513513
index++;
514+
// Ensure the project is upto date before checking if this file is present in the project
515+
project.updateGraph();
514516
if (!project.containsFile(fileName, requireOpen)) {
515517
return;
516518
}

src/testRunner/unittests/tsserverProjectSystem.ts

Lines changed: 137 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ namespace ts.projectSystem {
5858
getLogFileName: () => undefined,
5959
};
6060

61+
function createHasErrorMessageLogger() {
62+
let hasErrorMsg = false;
63+
const { close, hasLevel, loggingEnabled, startGroup, endGroup, info, getLogFileName, perftrc } = nullLogger;
64+
const logger: server.Logger = {
65+
close, hasLevel, loggingEnabled, startGroup, endGroup, info, getLogFileName, perftrc,
66+
msg: () => {
67+
hasErrorMsg = true;
68+
}
69+
};
70+
return { logger, hasErrorMsg: () => hasErrorMsg };
71+
}
72+
6173
export class TestTypingsInstaller extends TI.TypingsInstaller implements server.ITypingsInstaller {
6274
protected projectService: server.ProjectService;
6375
constructor(
@@ -2913,14 +2925,7 @@ namespace ts.projectSystem {
29132925
});
29142926

29152927
it("Getting errors from closed script info does not throw exception (because of getting project from orphan script info)", () => {
2916-
let hasErrorMsg = false;
2917-
const { close, hasLevel, loggingEnabled, startGroup, endGroup, info, getLogFileName, perftrc } = nullLogger;
2918-
const logger: server.Logger = {
2919-
close, hasLevel, loggingEnabled, startGroup, endGroup, info, getLogFileName, perftrc,
2920-
msg: () => {
2921-
hasErrorMsg = true;
2922-
}
2923-
};
2928+
const { logger, hasErrorMsg } = createHasErrorMessageLogger();
29242929
const f1 = {
29252930
path: "/a/b/app.ts",
29262931
content: "let x = 1;"
@@ -2950,7 +2955,7 @@ namespace ts.projectSystem {
29502955
files: [f1.path]
29512956
}
29522957
});
2953-
assert.isFalse(hasErrorMsg);
2958+
assert.isFalse(hasErrorMsg());
29542959
});
29552960

29562961
it("Changed module resolution reflected when specifying files list", () => {
@@ -3316,6 +3321,129 @@ namespace ts.projectSystem {
33163321
assert.equal(info.containingProjects.length, 0);
33173322
}
33183323
});
3324+
3325+
it("handles delayed directory watch invoke on file creation", () => {
3326+
const projectRootPath = "/users/username/projects/project";
3327+
const fileB: File = {
3328+
path: `${projectRootPath}/b.ts`,
3329+
content: "export const b = 10;"
3330+
};
3331+
const fileA: File = {
3332+
path: `${projectRootPath}/a.ts`,
3333+
content: "export const a = 10;"
3334+
};
3335+
const fileSubA: File = {
3336+
path: `${projectRootPath}/sub/a.ts`,
3337+
content: fileA.content
3338+
};
3339+
const config: File = {
3340+
path: `${projectRootPath}/tsconfig.json`,
3341+
content: "{}"
3342+
};
3343+
const files = [fileSubA, fileB, config, libFile];
3344+
const host = createServerHost(files);
3345+
const { logger, hasErrorMsg } = createHasErrorMessageLogger();
3346+
const session = createSession(host, { canUseEvents: true, noGetErrOnBackgroundUpdate: true, logger });
3347+
openFile(fileB);
3348+
openFile(fileSubA);
3349+
3350+
const services = session.getProjectService();
3351+
checkNumberOfProjects(services, { configuredProjects: 1 });
3352+
checkProjectActualFiles(services.configuredProjects.get(config.path)!, files.map(f => f.path));
3353+
host.checkTimeoutQueueLengthAndRun(0);
3354+
3355+
// This should schedule 2 timeouts for ensuring project structure and ensuring projects for open file
3356+
const filesWithFileA = files.map(f => f === fileSubA ? fileA : f);
3357+
host.reloadFS(files.map(f => f === fileSubA ? fileA : f));
3358+
host.checkTimeoutQueueLength(2);
3359+
3360+
closeFile(fileSubA);
3361+
// This should cancel existing updates and schedule new ones
3362+
host.checkTimeoutQueueLength(2);
3363+
checkNumberOfProjects(services, { configuredProjects: 1 });
3364+
checkProjectActualFiles(services.configuredProjects.get(config.path)!, files.map(f => f.path));
3365+
3366+
// Open the fileA (as if rename)
3367+
openFile(fileA);
3368+
3369+
// config project is updated to check if fileA is present in it
3370+
checkNumberOfProjects(services, { configuredProjects: 1 });
3371+
checkProjectActualFiles(services.configuredProjects.get(config.path)!, filesWithFileA.map(f => f.path));
3372+
3373+
// Run the timeout for updating configured project and ensuring projects for open file
3374+
host.checkTimeoutQueueLengthAndRun(2);
3375+
checkProjectActualFiles(services.configuredProjects.get(config.path)!, filesWithFileA.map(f => f.path));
3376+
3377+
// file is deleted but watches are not yet invoked
3378+
const originalFileExists = host.fileExists;
3379+
host.fileExists = s => s === fileA.path ? false : originalFileExists.call(host, s);
3380+
closeFile(fileA);
3381+
host.checkTimeoutQueueLength(2); // Update configured project and projects for open file
3382+
checkProjectActualFiles(services.configuredProjects.get(config.path)!, filesWithFileA.map(f => f.path));
3383+
3384+
// host.fileExists = originalFileExists;
3385+
openFile(fileSubA);
3386+
// This should create inferred project since fileSubA not on the disk
3387+
checkProjectActualFiles(services.configuredProjects.get(config.path)!, mapDefined(filesWithFileA, f => f === fileA ? undefined : f.path));
3388+
checkProjectActualFiles(services.inferredProjects[0], [fileSubA.path, libFile.path]);
3389+
3390+
host.checkTimeoutQueueLengthAndRun(2); // Update configured project and projects for open file
3391+
host.fileExists = originalFileExists;
3392+
3393+
// Actually trigger the file move
3394+
host.reloadFS(files);
3395+
host.checkTimeoutQueueLength(2);
3396+
const fileBErrorTimeoutId = host.getNextTimeoutId();
3397+
3398+
session.executeCommandSeq<protocol.GeterrRequest>({
3399+
command: protocol.CommandTypes.Geterr,
3400+
arguments: {
3401+
files: [fileB.path, fileSubA.path],
3402+
delay: 0
3403+
}
3404+
});
3405+
const getErrSeqId = session.getSeq();
3406+
host.checkTimeoutQueueLength(3);
3407+
3408+
session.clearMessages();
3409+
host.runQueuedTimeoutCallbacks(fileBErrorTimeoutId);
3410+
checkErrorMessage(session, "syntaxDiag", { file: fileB.path, diagnostics: [] });
3411+
3412+
session.clearMessages();
3413+
host.runQueuedImmediateCallbacks();
3414+
checkErrorMessage(session, "semanticDiag", { file: fileB.path, diagnostics: [] });
3415+
3416+
session.clearMessages();
3417+
const fileSubAErrorTimeoutId = host.getNextTimeoutId();
3418+
host.runQueuedImmediateCallbacks();
3419+
checkErrorMessage(session, "suggestionDiag", { file: fileB.path, diagnostics: [] });
3420+
3421+
session.clearMessages();
3422+
host.checkTimeoutQueueLength(3);
3423+
host.runQueuedTimeoutCallbacks(fileSubAErrorTimeoutId);
3424+
checkCompleteEvent(session, 1, getErrSeqId);
3425+
assert.isFalse(hasErrorMsg());
3426+
3427+
function openFile(file: File) {
3428+
session.executeCommandSeq<protocol.OpenRequest>({
3429+
command: protocol.CommandTypes.Open,
3430+
arguments: {
3431+
file: file.path,
3432+
fileContent: file.content,
3433+
projectRootPath
3434+
}
3435+
});
3436+
}
3437+
3438+
function closeFile(file: File) {
3439+
session.executeCommandSeq<protocol.CloseRequest>({
3440+
command: protocol.CommandTypes.Close,
3441+
arguments: {
3442+
file: file.path
3443+
}
3444+
});
3445+
}
3446+
});
33193447
});
33203448

33213449
describe("tsserverProjectSystem Proper errors", () => {
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(17,10): error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
2+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(20,13): error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
3+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(21,13): error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
4+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(26,10): error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
5+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(29,13): error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
6+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(30,13): error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
7+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(35,10): error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
8+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(38,13): error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
9+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(39,13): error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
10+
11+
12+
==== tests/cases/conformance/types/thisType/thisTypeAccessibility.ts (9 errors) ====
13+
class MyClass {
14+
private p: number = 123;
15+
protected pp: number = 123;
16+
public ppp: number = 123;
17+
private static sp: number = 123;
18+
protected static spp: number = 123;
19+
public static sppp: number = 123;
20+
}
21+
22+
interface MyClass {
23+
extension1(p: number): void;
24+
extension2(p: number): void;
25+
extension3(p: number): void;
26+
}
27+
28+
MyClass.prototype.extension1 = function (this: MyClass, p: number) {
29+
this.p = p;
30+
~
31+
!!! error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
32+
this.pp = p;
33+
this.ppp = p;
34+
MyClass.sp = p;
35+
~~
36+
!!! error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
37+
MyClass.spp = p;
38+
~~~
39+
!!! error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
40+
MyClass.sppp = p;
41+
}
42+
43+
MyClass.prototype.extension2 = function<T extends MyClass> (this: T, p: number) {
44+
this.p = p;
45+
~
46+
!!! error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
47+
this.pp = p;
48+
this.ppp = p;
49+
MyClass.sp = p;
50+
~~
51+
!!! error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
52+
MyClass.spp = p;
53+
~~~
54+
!!! error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
55+
MyClass.sppp = p;
56+
}
57+
58+
function extension3<T extends MyClass> (this: T, p: number) {
59+
this.p = p;
60+
~
61+
!!! error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
62+
this.pp = p;
63+
this.ppp = p;
64+
MyClass.sp = p;
65+
~~
66+
!!! error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
67+
MyClass.spp = p;
68+
~~~
69+
!!! error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
70+
MyClass.sppp = p;
71+
}
72+
73+
MyClass.prototype.extension3 = extension3;
74+

0 commit comments

Comments
 (0)