diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 7254f1c2a9..9509c28623 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -5643,7 +5643,7 @@ namespace ts {
}
if (source.flags & TypeFlags.Enum && target === numberType) return Ternary.True;
if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum) {
- if (result = enumRelatedTo(source, target)) {
+ if (result = enumRelatedTo(source, target, reportErrors)) {
return result;
}
}
@@ -6266,7 +6266,7 @@ namespace ts {
return Ternary.False;
}
- function enumRelatedTo(source: Type, target: Type) {
+ function enumRelatedTo(source: Type, target: Type, reportErrors?: boolean) {
if (source.symbol.name !== target.symbol.name ||
source.symbol.flags & SymbolFlags.ConstEnum ||
target.symbol.flags & SymbolFlags.ConstEnum) {
@@ -6277,9 +6277,11 @@ namespace ts {
if (property.flags & SymbolFlags.EnumMember) {
const targetProperty = getPropertyOfType(targetEnumType, property.name);
if (!targetProperty || !(targetProperty.flags & SymbolFlags.EnumMember)) {
- reportError(Diagnostics.Property_0_is_missing_in_type_1,
- property.name,
- typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType));
+ if (reportErrors) {
+ reportError(Diagnostics.Property_0_is_missing_in_type_1,
+ property.name,
+ typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType));
+ }
return Ternary.False;
}
}
diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts
index 7cdc162458..3856630ddf 100644
--- a/src/compiler/sys.ts
+++ b/src/compiler/sys.ts
@@ -1,8 +1,8 @@
///
namespace ts {
- export type FileWatcherCallback = (path: string, removed?: boolean) => void;
- export type DirectoryWatcherCallback = (path: string) => void;
+ export type FileWatcherCallback = (fileName: string, removed?: boolean) => void;
+ export type DirectoryWatcherCallback = (directoryName: string) => void;
export interface System {
args: string[];
@@ -12,7 +12,7 @@ namespace ts {
readFile(path: string, encoding?: string): string;
getFileSize?(path: string): number;
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
- watchFile?(path: Path, callback: FileWatcherCallback): FileWatcher;
+ watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
resolvePath(path: string): string;
fileExists(path: string): boolean;
@@ -27,7 +27,7 @@ namespace ts {
}
interface WatchedFile {
- filePath: Path;
+ fileName: string;
callback: FileWatcherCallback;
mtime?: Date;
}
@@ -37,7 +37,7 @@ namespace ts {
}
export interface DirectoryWatcher extends FileWatcher {
- directoryPath: Path;
+ directoryName: string;
referenceCount: number;
}
@@ -246,13 +246,13 @@ namespace ts {
return;
}
- _fs.stat(watchedFile.filePath, (err: any, stats: any) => {
+ _fs.stat(watchedFile.fileName, (err: any, stats: any) => {
if (err) {
- watchedFile.callback(watchedFile.filePath);
+ watchedFile.callback(watchedFile.fileName);
}
else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) {
- watchedFile.mtime = getModifiedTime(watchedFile.filePath);
- watchedFile.callback(watchedFile.filePath, watchedFile.mtime.getTime() === 0);
+ watchedFile.mtime = getModifiedTime(watchedFile.fileName);
+ watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0);
}
});
}
@@ -280,11 +280,11 @@ namespace ts {
}, interval);
}
- function addFile(filePath: Path, callback: FileWatcherCallback): WatchedFile {
+ function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
const file: WatchedFile = {
- filePath,
+ fileName,
callback,
- mtime: getModifiedTime(filePath)
+ mtime: getModifiedTime(fileName)
};
watchedFiles.push(file);
@@ -308,26 +308,26 @@ namespace ts {
}
function createWatchedFileSet() {
- const dirWatchers = createFileMap();
+ const dirWatchers: Map = {};
// One file can have multiple watchers
- const fileWatcherCallbacks = createFileMap();
+ const fileWatcherCallbacks: Map = {};
return { addFile, removeFile };
- function reduceDirWatcherRefCountForFile(filePath: Path) {
- const dirPath = getDirectoryPath(filePath);
- if (dirWatchers.contains(dirPath)) {
- const watcher = dirWatchers.get(dirPath);
+ function reduceDirWatcherRefCountForFile(fileName: string) {
+ const dirName = getDirectoryPath(fileName);
+ if (hasProperty(dirWatchers, dirName)) {
+ const watcher = dirWatchers[dirName];
watcher.referenceCount -= 1;
if (watcher.referenceCount <= 0) {
watcher.close();
- dirWatchers.remove(dirPath);
+ delete dirWatchers[dirName];
}
}
}
- function addDirWatcher(dirPath: Path): void {
- if (dirWatchers.contains(dirPath)) {
- const watcher = dirWatchers.get(dirPath);
+ function addDirWatcher(dirPath: string): void {
+ if (hasProperty(dirWatchers, dirPath)) {
+ const watcher = dirWatchers[dirPath];
watcher.referenceCount += 1;
return;
}
@@ -338,52 +338,52 @@ namespace ts {
(eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)
);
watcher.referenceCount = 1;
- dirWatchers.set(dirPath, watcher);
+ dirWatchers[dirPath] = watcher;
return;
}
- function addFileWatcherCallback(filePath: Path, callback: FileWatcherCallback): void {
- if (fileWatcherCallbacks.contains(filePath)) {
- fileWatcherCallbacks.get(filePath).push(callback);
+ function addFileWatcherCallback(filePath: string, callback: FileWatcherCallback): void {
+ if (hasProperty(fileWatcherCallbacks, filePath)) {
+ fileWatcherCallbacks[filePath].push(callback);
}
else {
- fileWatcherCallbacks.set(filePath, [callback]);
+ fileWatcherCallbacks[filePath] = [callback];
}
}
- function addFile(filePath: Path, callback: FileWatcherCallback): WatchedFile {
- addFileWatcherCallback(filePath, callback);
- addDirWatcher(getDirectoryPath(filePath));
+ function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
+ addFileWatcherCallback(fileName, callback);
+ addDirWatcher(getDirectoryPath(fileName));
- return { filePath, callback };
+ return { fileName, callback };
}
function removeFile(watchedFile: WatchedFile) {
- removeFileWatcherCallback(watchedFile.filePath, watchedFile.callback);
- reduceDirWatcherRefCountForFile(watchedFile.filePath);
+ removeFileWatcherCallback(watchedFile.fileName, watchedFile.callback);
+ reduceDirWatcherRefCountForFile(watchedFile.fileName);
}
- function removeFileWatcherCallback(filePath: Path, callback: FileWatcherCallback) {
- if (fileWatcherCallbacks.contains(filePath)) {
- const newCallbacks = copyListRemovingItem(callback, fileWatcherCallbacks.get(filePath));
+ function removeFileWatcherCallback(filePath: string, callback: FileWatcherCallback) {
+ if (hasProperty(fileWatcherCallbacks, filePath)) {
+ const newCallbacks = copyListRemovingItem(callback, fileWatcherCallbacks[filePath]);
if (newCallbacks.length === 0) {
- fileWatcherCallbacks.remove(filePath);
+ delete fileWatcherCallbacks[filePath];
}
else {
- fileWatcherCallbacks.set(filePath, newCallbacks);
+ fileWatcherCallbacks[filePath] = newCallbacks;
}
}
}
- function fileEventHandler(eventName: string, relativeFileName: string, baseDirPath: Path) {
+ function fileEventHandler(eventName: string, relativeFileName: string, baseDirPath: string) {
// When files are deleted from disk, the triggered "rename" event would have a relativefileName of "undefined"
- const filePath = typeof relativeFileName !== "string"
+ const fileName = typeof relativeFileName !== "string"
? undefined
- : toPath(relativeFileName, baseDirPath, createGetCanonicalFileName(sys.useCaseSensitiveFileNames));
+ : ts.getNormalizedAbsolutePath(relativeFileName, baseDirPath);
// Some applications save a working file via rename operations
- if ((eventName === "change" || eventName === "rename") && fileWatcherCallbacks.contains(filePath)) {
- for (const fileCallback of fileWatcherCallbacks.get(filePath)) {
- fileCallback(filePath);
+ if ((eventName === "change" || eventName === "rename") && hasProperty(fileWatcherCallbacks, fileName)) {
+ for (const fileCallback of fileWatcherCallbacks[fileName]) {
+ fileCallback(fileName);
}
}
}
@@ -495,6 +495,11 @@ namespace ts {
const files = _fs.readdirSync(path || ".").sort();
const directories: string[] = [];
for (const current of files) {
+ // This is necessary because on some file system node fails to exclude
+ // "." and "..". See https://github.com/nodejs/node/issues/4002
+ if (current === "." || current === "..") {
+ continue;
+ }
const name = combinePaths(path, current);
if (!contains(exclude, getCanonicalPath(name))) {
// fs.statSync would throw an exception if the file is a symlink
@@ -553,18 +558,18 @@ namespace ts {
},
readFile,
writeFile,
- watchFile: (filePath, callback) => {
+ watchFile: (fileName, callback) => {
// Node 4.0 stabilized the `fs.watch` function on Windows which avoids polling
// and is more efficient than `fs.watchFile` (ref: https://github.com/nodejs/node/pull/2649
// and https://github.com/Microsoft/TypeScript/issues/4643), therefore
// if the current node.js version is newer than 4, use `fs.watch` instead.
const watchSet = isNode4OrLater() ? watchedFileSet : pollingWatchedFileSet;
- const watchedFile = watchSet.addFile(filePath, callback);
+ const watchedFile = watchSet.addFile(fileName, callback);
return {
close: () => watchSet.removeFile(watchedFile)
};
},
- watchDirectory: (path, callback, recursive) => {
+ watchDirectory: (directoryName, callback, recursive) => {
// Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows
// (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
let options: any;
@@ -576,7 +581,7 @@ namespace ts {
}
return _fs.watch(
- path,
+ directoryName,
options,
(eventName: string, relativeFileName: string) => {
// In watchDirectory we only care about adding and removing files (when event name is
@@ -584,7 +589,7 @@ namespace ts {
// event name is "change")
if (eventName === "rename") {
// When deleting a file, the passed baseFileName is null
- callback(!relativeFileName ? relativeFileName : normalizePath(combinePaths(path, relativeFileName)));
+ callback(!relativeFileName ? relativeFileName : normalizePath(combinePaths(directoryName, relativeFileName)));
};
}
);
diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts
index ba7a5f20da..2fba2d1329 100644
--- a/src/harness/fourslash.ts
+++ b/src/harness/fourslash.ts
@@ -1414,7 +1414,7 @@ namespace FourSlash {
return;
}
- const incrementalSourceFile = this.languageService.getSourceFile(this.activeFile.fileName);
+ const incrementalSourceFile = this.languageService.getNonBoundSourceFile(this.activeFile.fileName);
Utils.assertInvariants(incrementalSourceFile, /*parent:*/ undefined);
const incrementalSyntaxDiagnostics = incrementalSourceFile.parseDiagnostics;
diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts
index 2a6ed85f9c..12bb6a470e 100644
--- a/src/harness/harnessLanguageService.ts
+++ b/src/harness/harnessLanguageService.ts
@@ -423,7 +423,7 @@ namespace Harness.LanguageService {
getProgram(): ts.Program {
throw new Error("Program can not be marshaled across the shim layer.");
}
- getSourceFile(fileName: string): ts.SourceFile {
+ getNonBoundSourceFile(fileName: string): ts.SourceFile {
throw new Error("SourceFile can not be marshaled across the shim layer.");
}
dispose(): void { this.shim.dispose({}); }
diff --git a/src/server/client.ts b/src/server/client.ts
index 8731c52cc7..957d36e4a3 100644
--- a/src/server/client.ts
+++ b/src/server/client.ts
@@ -613,7 +613,7 @@ namespace ts.server {
throw new Error("SourceFile objects are not serializable through the server protocol.");
}
- getSourceFile(fileName: string): SourceFile {
+ getNonBoundSourceFile(fileName: string): SourceFile {
throw new Error("SourceFile objects are not serializable through the server protocol.");
}
diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts
index 2c9e26e47c..98a0200916 100644
--- a/src/server/editorServices.ts
+++ b/src/server/editorServices.ts
@@ -1082,9 +1082,7 @@ namespace ts.server {
info.setFormatOptions(this.getFormatCodeOptions());
this.filenameToScriptInfo[fileName] = info;
if (!info.isOpen) {
- info.fileWatcher = this.host.watchFile(
- toPath(fileName, fileName, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)),
- _ => { this.watchedFileChanged(fileName); });
+ info.fileWatcher = this.host.watchFile(fileName, _ => { this.watchedFileChanged(fileName); });
}
}
}
@@ -1336,9 +1334,7 @@ namespace ts.server {
}
}
project.finishGraph();
- project.projectFileWatcher = this.host.watchFile(
- toPath(configFilename, configFilename, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)),
- _ => this.watchedProjectConfigFileChanged(project));
+ project.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(project));
this.log("Add recursive watcher for: " + ts.getDirectoryPath(configFilename));
project.directoryWatcher = this.host.watchDirectory(
ts.getDirectoryPath(configFilename),
@@ -1479,7 +1475,7 @@ namespace ts.server {
}
isExternalModule(filename: string): boolean {
- const sourceFile = this.languageService.getSourceFile(filename);
+ const sourceFile = this.languageService.getNonBoundSourceFile(filename);
return ts.isExternalModule(sourceFile);
}
diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts
index effaa53bc1..1d7e968444 100644
--- a/src/services/navigationBar.ts
+++ b/src/services/navigationBar.ts
@@ -160,6 +160,20 @@ namespace ts.NavigationBar {
for (let node of nodes) {
switch (node.kind) {
case SyntaxKind.ClassDeclaration:
+ topLevelNodes.push(node);
+ for (const member of (node).members) {
+ if (member.kind === SyntaxKind.MethodDeclaration || member.kind === SyntaxKind.Constructor) {
+ type FunctionLikeMember = MethodDeclaration | ConstructorDeclaration;
+ if ((member).body) {
+ // We do not include methods that does not have child functions in it, because of duplications.
+ if (hasNamedFunctionDeclarations(((member).body).statements)) {
+ topLevelNodes.push(member);
+ }
+ addTopLevelNodes(((member).body).statements, topLevelNodes);
+ }
+ }
+ }
+ break;
case SyntaxKind.EnumDeclaration:
case SyntaxKind.InterfaceDeclaration:
topLevelNodes.push(node);
@@ -182,23 +196,40 @@ namespace ts.NavigationBar {
}
}
- function isTopLevelFunctionDeclaration(functionDeclaration: FunctionLikeDeclaration) {
+ function hasNamedFunctionDeclarations(nodes: NodeArray): boolean {
+ for (let s of nodes) {
+ if (s.kind === SyntaxKind.FunctionDeclaration && !isEmpty((s).name.text)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function isTopLevelFunctionDeclaration(functionDeclaration: FunctionLikeDeclaration): boolean {
if (functionDeclaration.kind === SyntaxKind.FunctionDeclaration) {
// A function declaration is 'top level' if it contains any function declarations
// within it.
if (functionDeclaration.body && functionDeclaration.body.kind === SyntaxKind.Block) {
// Proper function declarations can only have identifier names
- if (forEach((functionDeclaration.body).statements,
- s => s.kind === SyntaxKind.FunctionDeclaration && !isEmpty((s).name.text))) {
-
+ if (hasNamedFunctionDeclarations((functionDeclaration.body).statements)) {
return true;
}
- // Or if it is not parented by another function. i.e all functions
- // at module scope are 'top level'.
+ // Or if it is not parented by another function. I.e all functions at module scope are 'top level'.
if (!isFunctionBlock(functionDeclaration.parent)) {
return true;
}
+
+ // Or if it is nested inside class methods and constructors.
+ else {
+ // We have made sure that a grand parent node exists with 'isFunctionBlock()' above.
+ const grandParentKind = functionDeclaration.parent.parent.kind;
+ if (grandParentKind === SyntaxKind.MethodDeclaration ||
+ grandParentKind === SyntaxKind.Constructor) {
+
+ return true;
+ }
+ }
}
}
@@ -376,6 +407,10 @@ namespace ts.NavigationBar {
case SyntaxKind.ClassDeclaration:
return createClassItem(node);
+ case SyntaxKind.MethodDeclaration:
+ case SyntaxKind.Constructor:
+ return createMemberFunctionLikeItem(node);
+
case SyntaxKind.EnumDeclaration:
return createEnumItem(node);
@@ -424,11 +459,11 @@ namespace ts.NavigationBar {
getIndent(node));
}
- function createFunctionItem(node: FunctionDeclaration) {
+ function createFunctionItem(node: FunctionDeclaration): ts.NavigationBarItem {
if (node.body && node.body.kind === SyntaxKind.Block) {
let childItems = getItemsWorker(sortNodes((node.body).statements), createChildItem);
- return getNavigationBarItem(!node.name ? "default": node.name.text ,
+ return getNavigationBarItem(!node.name ? "default": node.name.text,
ts.ScriptElementKind.functionElement,
getNodeModifiers(node),
[getNodeSpan(node)],
@@ -439,6 +474,31 @@ namespace ts.NavigationBar {
return undefined;
}
+ function createMemberFunctionLikeItem(node: MethodDeclaration | ConstructorDeclaration): ts.NavigationBarItem {
+ if (node.body && node.body.kind === SyntaxKind.Block) {
+ let childItems = getItemsWorker(sortNodes((node.body).statements), createChildItem);
+ let scriptElementKind: string;
+ let memberFunctionName: string;
+ if (node.kind === SyntaxKind.MethodDeclaration) {
+ memberFunctionName = getPropertyNameForPropertyNameNode(node.name);
+ scriptElementKind = ts.ScriptElementKind.memberFunctionElement;
+ }
+ else {
+ memberFunctionName = "constructor";
+ scriptElementKind = ts.ScriptElementKind.constructorImplementationElement;
+ }
+
+ return getNavigationBarItem(memberFunctionName,
+ scriptElementKind,
+ getNodeModifiers(node),
+ [getNodeSpan(node)],
+ childItems,
+ getIndent(node));
+ }
+
+ return undefined;
+ }
+
function createSourceFileItem(node: SourceFile): ts.NavigationBarItem {
let childItems = getItemsWorker(getChildNodes(node.statements), createChildItem);
diff --git a/src/services/services.ts b/src/services/services.ts
index 5f228f7d53..f587b6be23 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -1112,7 +1112,7 @@ namespace ts {
getProgram(): Program;
- getSourceFile(fileName: string): SourceFile;
+ /* @internal */ getNonBoundSourceFile(fileName: string): SourceFile;
dispose(): void;
}
@@ -6529,7 +6529,7 @@ namespace ts {
}
/// Syntactic features
- function getSourceFile(fileName: string): SourceFile {
+ function getNonBoundSourceFile(fileName: string): SourceFile {
return syntaxTreeCache.getCurrentSourceFile(fileName);
}
@@ -7617,7 +7617,7 @@ namespace ts {
getFormattingEditsAfterKeystroke,
getDocCommentTemplateAtPosition,
getEmitOutput,
- getSourceFile,
+ getNonBoundSourceFile,
getProgram
};
}
diff --git a/tests/baselines/reference/enumAssignmentCompat4.js b/tests/baselines/reference/enumAssignmentCompat4.js
new file mode 100644
index 0000000000..ad28324ce0
--- /dev/null
+++ b/tests/baselines/reference/enumAssignmentCompat4.js
@@ -0,0 +1,51 @@
+//// [enumAssignmentCompat4.ts]
+namespace M {
+ export enum MyEnum {
+ BAR
+ }
+ export var object2 = {
+ foo: MyEnum.BAR
+ };
+}
+
+namespace N {
+ export enum MyEnum {
+ FOO
+ };
+ export var object1 = {
+ foo: MyEnum.FOO
+ };
+}
+
+let broken = [
+ N.object1,
+ M.object2
+];
+
+
+//// [enumAssignmentCompat4.js]
+var M;
+(function (M) {
+ (function (MyEnum) {
+ MyEnum[MyEnum["BAR"] = 0] = "BAR";
+ })(M.MyEnum || (M.MyEnum = {}));
+ var MyEnum = M.MyEnum;
+ M.object2 = {
+ foo: MyEnum.BAR
+ };
+})(M || (M = {}));
+var N;
+(function (N) {
+ (function (MyEnum) {
+ MyEnum[MyEnum["FOO"] = 0] = "FOO";
+ })(N.MyEnum || (N.MyEnum = {}));
+ var MyEnum = N.MyEnum;
+ ;
+ N.object1 = {
+ foo: MyEnum.FOO
+ };
+})(N || (N = {}));
+var broken = [
+ N.object1,
+ M.object2
+];
diff --git a/tests/baselines/reference/enumAssignmentCompat4.symbols b/tests/baselines/reference/enumAssignmentCompat4.symbols
new file mode 100644
index 0000000000..a3a8073161
--- /dev/null
+++ b/tests/baselines/reference/enumAssignmentCompat4.symbols
@@ -0,0 +1,59 @@
+=== tests/cases/compiler/enumAssignmentCompat4.ts ===
+namespace M {
+>M : Symbol(M, Decl(enumAssignmentCompat4.ts, 0, 0))
+
+ export enum MyEnum {
+>MyEnum : Symbol(MyEnum, Decl(enumAssignmentCompat4.ts, 0, 13))
+
+ BAR
+>BAR : Symbol(MyEnum.BAR, Decl(enumAssignmentCompat4.ts, 1, 24))
+ }
+ export var object2 = {
+>object2 : Symbol(object2, Decl(enumAssignmentCompat4.ts, 4, 14))
+
+ foo: MyEnum.BAR
+>foo : Symbol(foo, Decl(enumAssignmentCompat4.ts, 4, 26))
+>MyEnum.BAR : Symbol(MyEnum.BAR, Decl(enumAssignmentCompat4.ts, 1, 24))
+>MyEnum : Symbol(MyEnum, Decl(enumAssignmentCompat4.ts, 0, 13))
+>BAR : Symbol(MyEnum.BAR, Decl(enumAssignmentCompat4.ts, 1, 24))
+
+ };
+}
+
+namespace N {
+>N : Symbol(N, Decl(enumAssignmentCompat4.ts, 7, 1))
+
+ export enum MyEnum {
+>MyEnum : Symbol(MyEnum, Decl(enumAssignmentCompat4.ts, 9, 13))
+
+ FOO
+>FOO : Symbol(MyEnum.FOO, Decl(enumAssignmentCompat4.ts, 10, 24))
+
+ };
+ export var object1 = {
+>object1 : Symbol(object1, Decl(enumAssignmentCompat4.ts, 13, 14))
+
+ foo: MyEnum.FOO
+>foo : Symbol(foo, Decl(enumAssignmentCompat4.ts, 13, 26))
+>MyEnum.FOO : Symbol(MyEnum.FOO, Decl(enumAssignmentCompat4.ts, 10, 24))
+>MyEnum : Symbol(MyEnum, Decl(enumAssignmentCompat4.ts, 9, 13))
+>FOO : Symbol(MyEnum.FOO, Decl(enumAssignmentCompat4.ts, 10, 24))
+
+ };
+}
+
+let broken = [
+>broken : Symbol(broken, Decl(enumAssignmentCompat4.ts, 18, 3))
+
+ N.object1,
+>N.object1 : Symbol(N.object1, Decl(enumAssignmentCompat4.ts, 13, 14))
+>N : Symbol(N, Decl(enumAssignmentCompat4.ts, 7, 1))
+>object1 : Symbol(N.object1, Decl(enumAssignmentCompat4.ts, 13, 14))
+
+ M.object2
+>M.object2 : Symbol(M.object2, Decl(enumAssignmentCompat4.ts, 4, 14))
+>M : Symbol(M, Decl(enumAssignmentCompat4.ts, 0, 0))
+>object2 : Symbol(M.object2, Decl(enumAssignmentCompat4.ts, 4, 14))
+
+];
+
diff --git a/tests/baselines/reference/enumAssignmentCompat4.types b/tests/baselines/reference/enumAssignmentCompat4.types
new file mode 100644
index 0000000000..db7f5ce8ba
--- /dev/null
+++ b/tests/baselines/reference/enumAssignmentCompat4.types
@@ -0,0 +1,62 @@
+=== tests/cases/compiler/enumAssignmentCompat4.ts ===
+namespace M {
+>M : typeof M
+
+ export enum MyEnum {
+>MyEnum : MyEnum
+
+ BAR
+>BAR : MyEnum
+ }
+ export var object2 = {
+>object2 : { foo: MyEnum; }
+>{ foo: MyEnum.BAR } : { foo: MyEnum; }
+
+ foo: MyEnum.BAR
+>foo : MyEnum
+>MyEnum.BAR : MyEnum
+>MyEnum : typeof MyEnum
+>BAR : MyEnum
+
+ };
+}
+
+namespace N {
+>N : typeof N
+
+ export enum MyEnum {
+>MyEnum : MyEnum
+
+ FOO
+>FOO : MyEnum
+
+ };
+ export var object1 = {
+>object1 : { foo: MyEnum; }
+>{ foo: MyEnum.FOO } : { foo: MyEnum; }
+
+ foo: MyEnum.FOO
+>foo : MyEnum
+>MyEnum.FOO : MyEnum
+>MyEnum : typeof MyEnum
+>FOO : MyEnum
+
+ };
+}
+
+let broken = [
+>broken : ({ foo: N.MyEnum; } | { foo: M.MyEnum; })[]
+>[ N.object1, M.object2] : ({ foo: N.MyEnum; } | { foo: M.MyEnum; })[]
+
+ N.object1,
+>N.object1 : { foo: N.MyEnum; }
+>N : typeof N
+>object1 : { foo: N.MyEnum; }
+
+ M.object2
+>M.object2 : { foo: M.MyEnum; }
+>M : typeof M
+>object2 : { foo: M.MyEnum; }
+
+];
+
diff --git a/tests/cases/compiler/enumAssignmentCompat4.ts b/tests/cases/compiler/enumAssignmentCompat4.ts
new file mode 100644
index 0000000000..0a5fc89660
--- /dev/null
+++ b/tests/cases/compiler/enumAssignmentCompat4.ts
@@ -0,0 +1,22 @@
+namespace M {
+ export enum MyEnum {
+ BAR
+ }
+ export var object2 = {
+ foo: MyEnum.BAR
+ };
+}
+
+namespace N {
+ export enum MyEnum {
+ FOO
+ };
+ export var object1 = {
+ foo: MyEnum.FOO
+ };
+}
+
+let broken = [
+ N.object1,
+ M.object2
+];
diff --git a/tests/cases/fourslash/navigationBarItemsInsideMethodsAndConstructors.ts b/tests/cases/fourslash/navigationBarItemsInsideMethodsAndConstructors.ts
new file mode 100644
index 0000000000..4dcca43af3
--- /dev/null
+++ b/tests/cases/fourslash/navigationBarItemsInsideMethodsAndConstructors.ts
@@ -0,0 +1,42 @@
+///
+
+////class Class {
+//// constructor() {
+//// {| "itemName": "LocalFunctionInConstructor", "kind": "function", "parentName": "Class"|}function LocalFunctionInConstructor() {
+////
+//// }
+////
+//// {| "itemName": "LocalInterfaceInConstrcutor", "kind": "interface", "parentName": "foo"|}interface LocalInterfaceInConstrcutor {
+//// }
+////
+//// enum LocalEnumInConstructor {
+//// {| "itemName": "LocalEnumMemberInConstructor", "kind": "property", "parentName": "LocalEnumInConstructor"|}LocalEnumMemberInConstructor,
+//// }
+//// }
+////
+//// method() {
+//// {| "itemName": "LocalFunctionInMethod", "kind": "function", "parentName": "foo"|}function LocalFunctionInMethod() {
+//// {| "itemName": "LocalFunctionInLocalFunctionInMethod", "kind": "function", "parentName": "bar"|}function LocalFunctionInLocalFunctionInMethod() {
+////
+//// }
+//// }
+////
+//// {| "itemName": "LocalInterfaceInMethod", "kind": "interface", "parentName": "foo"|}interface LocalInterfaceInMethod {
+//// }
+////
+//// enum LocalEnumInMethod {
+//// {| "itemName": "LocalEnumMemberInMethod", "kind": "property", "parentName": "foo"|}LocalEnumMemberInMethod,
+//// }
+//// }
+////
+//// emptyMethod() { // Non child functions method should not be duplicated
+////
+//// }
+////}
+
+test.markers().forEach((marker) => {
+ verify.getScriptLexicalStructureListContains(marker.data.itemName, marker.data.kind, marker.fileName, marker.data.parentName);
+});
+
+// no other items
+verify.getScriptLexicalStructureListCount(17);