Merge branch 'master' into addUndefinedCheckToCollectLinkedAliases

This commit is contained in:
Mohamed Hegazy
2016-01-15 14:40:04 -08:00
67 changed files with 1341 additions and 89 deletions
+44 -5
View File
@@ -741,7 +741,9 @@ namespace ts {
if (!result) {
if (nameNotFoundMessage) {
error(errorLocation, nameNotFoundMessage, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg));
if (!checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg)) {
error(errorLocation, nameNotFoundMessage, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg));
}
}
return undefined;
}
@@ -778,6 +780,43 @@ namespace ts {
return result;
}
function checkAndReportErrorForMissingPrefix(errorLocation: Node, name: string, nameArg: string | Identifier): boolean {
if (!errorLocation || (errorLocation.kind === SyntaxKind.Identifier && (isTypeReferenceIdentifier(<Identifier>errorLocation)) || isInTypeQuery(errorLocation))) {
return false;
}
const container = getThisContainer(errorLocation, /* includeArrowFunctions */ true);
let location = container;
while (location) {
if (isClassLike(location.parent)) {
const classSymbol = getSymbolOfNode(location.parent);
if (!classSymbol) {
break;
}
// Check to see if a static member exists.
const constructorType = getTypeOfSymbol(classSymbol);
if (getPropertyOfType(constructorType, name)) {
error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg), symbolToString(classSymbol));
return true;
}
// No static member is present.
// Check if we're in an instance method and look for a relevant instance member.
if (location === container && !(location.flags & NodeFlags.Static)) {
const instanceType = (<InterfaceType>getDeclaredTypeOfSymbol(classSymbol)).thisType;
if (getPropertyOfType(instanceType, name)) {
error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg));
return true;
}
}
}
location = location.parent;
}
return false;
}
function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void {
Debug.assert((result.flags & SymbolFlags.BlockScopedVariable) !== 0);
// Block-scoped variables cannot be used before their definition
@@ -6688,10 +6727,6 @@ namespace ts {
if (typeInfo && typeInfo.type === undefinedType) {
return type;
}
// If the type to be narrowed is any and we're checking a primitive with assumeTrue=true, return the primitive
if (!!(type.flags & TypeFlags.Any) && typeInfo && assumeTrue) {
return typeInfo.type;
}
let flags: TypeFlags;
if (typeInfo) {
flags = typeInfo.flags;
@@ -6702,6 +6737,10 @@ namespace ts {
}
// At this point we can bail if it's not a union
if (!(type.flags & TypeFlags.Union)) {
// If we're on the true branch and the type is a subtype, we should return the primitive type
if (assumeTrue && typeInfo && isTypeSubtypeOf(typeInfo.type, type)) {
return typeInfo.type;
}
// If the active non-union type would be removed from a union by this type guard, return an empty union
return filterUnion(type) ? type : emptyUnionType;
}
+10 -1
View File
@@ -616,7 +616,9 @@ namespace ts {
return path.substr(0, rootLength) + normalized.join(directorySeparator);
}
export function getDirectoryPath(path: string) {
export function getDirectoryPath(path: Path): Path;
export function getDirectoryPath(path: string): string;
export function getDirectoryPath(path: string): any {
return path.substr(0, Math.max(getRootLength(path), path.lastIndexOf(directorySeparator)));
}
@@ -874,4 +876,11 @@ namespace ts {
}
return copiedList;
}
export function createGetCanonicalFileName(useCaseSensitivefileNames: boolean): (fileName: string) => string {
return useCaseSensitivefileNames
? ((fileName) => fileName)
: ((fileName) => fileName.toLowerCase());
}
}
+8
View File
@@ -1767,6 +1767,14 @@
"category": "Error",
"code": 2661
},
"Cannot find name '{0}'. Did you mean the static member '{1}.{0}'?": {
"category": "Error",
"code": 2662
},
"Cannot find name '{0}'. Did you mean the instance member 'this.{0}'?": {
"category": "Error",
"code": 2663
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
"code": 4000
+2 -1
View File
@@ -2886,7 +2886,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.ForOfStatement:
if ((<ForStatement | ForInStatement | ForOfStatement>node).initializer.kind === SyntaxKind.VariableDeclarationList) {
const initializer = (<ForStatement | ForInStatement | ForOfStatement>node).initializer;
if (initializer && initializer.kind === SyntaxKind.VariableDeclarationList) {
loopInitializer = <VariableDeclarationList>(<ForStatement | ForInStatement | ForOfStatement>node).initializer;
}
break;
+124 -22
View File
@@ -1,6 +1,9 @@
/// <reference path="core.ts"/>
namespace ts {
export type FileWatcherCallback = (path: string, removed?: boolean) => void;
export type DirectoryWatcherCallback = (path: string) => void;
export interface System {
args: string[];
newLine: string;
@@ -8,8 +11,8 @@ namespace ts {
write(s: string): void;
readFile(path: string, encoding?: string): string;
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
watchFile?(path: string, callback: (path: string, removed?: boolean) => void): FileWatcher;
watchDirectory?(path: string, callback: (path: string) => void, recursive?: boolean): FileWatcher;
watchFile?(path: Path, callback: FileWatcherCallback): FileWatcher;
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
resolvePath(path: string): string;
fileExists(path: string): boolean;
directoryExists(path: string): boolean;
@@ -22,15 +25,20 @@ namespace ts {
}
interface WatchedFile {
fileName: string;
callback: (fileName: string, removed?: boolean) => void;
mtime: Date;
filePath: Path;
callback: FileWatcherCallback;
mtime?: Date;
}
export interface FileWatcher {
close(): void;
}
export interface DirectoryWatcher extends FileWatcher {
directoryPath: Path;
referenceCount: number;
}
declare var require: any;
declare var module: any;
declare var process: any;
@@ -62,8 +70,8 @@ namespace ts {
readFile(path: string): string;
writeFile(path: string, contents: string): void;
readDirectory(path: string, extension?: string, exclude?: string[]): string[];
watchFile?(path: string, callback: (path: string, removed?: boolean) => void): FileWatcher;
watchDirectory?(path: string, callback: (path: string) => void, recursive?: boolean): FileWatcher;
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
};
export var sys: System = (function () {
@@ -221,7 +229,7 @@ namespace ts {
// average async stat takes about 30 microseconds
// set chunk size to do 30 files in < 1 millisecond
function createWatchedFileSet(interval = 2500, chunkSize = 30) {
function createPollingWatchedFileSet(interval = 2500, chunkSize = 30) {
let watchedFiles: WatchedFile[] = [];
let nextFileToCheck = 0;
let watchTimer: any;
@@ -236,13 +244,13 @@ namespace ts {
return;
}
_fs.stat(watchedFile.fileName, (err: any, stats: any) => {
_fs.stat(watchedFile.filePath, (err: any, stats: any) => {
if (err) {
watchedFile.callback(watchedFile.fileName);
watchedFile.callback(watchedFile.filePath);
}
else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) {
watchedFile.mtime = getModifiedTime(watchedFile.fileName);
watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0);
watchedFile.mtime = getModifiedTime(watchedFile.filePath);
watchedFile.callback(watchedFile.filePath, watchedFile.mtime.getTime() === 0);
}
});
}
@@ -270,11 +278,11 @@ namespace ts {
}, interval);
}
function addFile(fileName: string, callback: (fileName: string, removed?: boolean) => void): WatchedFile {
function addFile(filePath: Path, callback: FileWatcherCallback): WatchedFile {
const file: WatchedFile = {
fileName,
filePath,
callback,
mtime: getModifiedTime(fileName)
mtime: getModifiedTime(filePath)
};
watchedFiles.push(file);
@@ -297,6 +305,88 @@ namespace ts {
};
}
function createWatchedFileSet() {
const dirWatchers = createFileMap<DirectoryWatcher>();
// One file can have multiple watchers
const fileWatcherCallbacks = createFileMap<FileWatcherCallback[]>();
return { addFile, removeFile };
function reduceDirWatcherRefCountForFile(filePath: Path) {
const dirPath = getDirectoryPath(filePath);
if (dirWatchers.contains(dirPath)) {
const watcher = dirWatchers.get(dirPath);
watcher.referenceCount -= 1;
if (watcher.referenceCount <= 0) {
watcher.close();
dirWatchers.remove(dirPath);
}
}
}
function addDirWatcher(dirPath: Path): void {
if (dirWatchers.contains(dirPath)) {
const watcher = dirWatchers.get(dirPath);
watcher.referenceCount += 1;
return;
}
const watcher: DirectoryWatcher = _fs.watch(
dirPath,
{ persistent: true },
(eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)
);
watcher.referenceCount = 1;
dirWatchers.set(dirPath, watcher);
return;
}
function addFileWatcherCallback(filePath: Path, callback: FileWatcherCallback): void {
if (fileWatcherCallbacks.contains(filePath)) {
fileWatcherCallbacks.get(filePath).push(callback);
}
else {
fileWatcherCallbacks.set(filePath, [callback]);
}
}
function addFile(filePath: Path, callback: FileWatcherCallback): WatchedFile {
addFileWatcherCallback(filePath, callback);
addDirWatcher(getDirectoryPath(filePath));
return { filePath, callback };
}
function removeFile(watchedFile: WatchedFile) {
removeFileWatcherCallback(watchedFile.filePath, watchedFile.callback);
reduceDirWatcherRefCountForFile(watchedFile.filePath);
}
function removeFileWatcherCallback(filePath: Path, callback: FileWatcherCallback) {
if (fileWatcherCallbacks.contains(filePath)) {
const newCallbacks = copyListRemovingItem(callback, fileWatcherCallbacks.get(filePath));
if (newCallbacks.length === 0) {
fileWatcherCallbacks.remove(filePath);
}
else {
fileWatcherCallbacks.set(filePath, newCallbacks);
}
}
}
/**
* @param watcherPath is the path from which the watcher is triggered.
*/
function fileEventHandler(eventName: string, relativefileName: string, baseDirPath: Path) {
// When files are deleted from disk, the triggered "rename" event would have a relativefileName of "undefined"
const filePath = relativefileName === undefined ? undefined : toPath(relativefileName, baseDirPath, getCanonicalPath);
if (eventName === "change" && fileWatcherCallbacks.contains(filePath)) {
for (const fileCallback of fileWatcherCallbacks.get(filePath)) {
fileCallback(filePath);
}
}
}
}
// REVIEW: for now this implementation uses polling.
// The advantage of polling is that it works reliably
// on all os and with network mounted files.
@@ -310,8 +400,13 @@ namespace ts {
// changes for large reference sets? If so, do we want
// to increase the chunk size or decrease the interval
// time dynamically to match the large reference set?
const pollingWatchedFileSet = createPollingWatchedFileSet();
const watchedFileSet = createWatchedFileSet();
function isNode4OrLater(): boolean {
return parseInt(process.version.charAt(1)) >= 4;
}
const platform: string = _os.platform();
// win32\win64 are case insensitive platforms, MacOS (darwin) by default is also case insensitive
const useCaseSensitiveFileNames = platform !== "win32" && platform !== "win64" && platform !== "darwin";
@@ -405,29 +500,38 @@ namespace ts {
},
readFile,
writeFile,
watchFile: (fileName, callback) => {
watchFile: (filePath, callback) => {
// Node 4.0 stablized 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 watchedFile = watchedFileSet.addFile(fileName, callback);
const watchSet = isNode4OrLater() ? watchedFileSet : pollingWatchedFileSet;
const watchedFile = watchSet.addFile(filePath, callback);
return {
close: () => watchedFileSet.removeFile(watchedFile)
close: () => watchSet.removeFile(watchedFile)
};
},
watchDirectory: (path, 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;
if (isNode4OrLater() && (process.platform === "win32" || process.platform === "darwin")) {
options = { persistent: true, recursive: !!recursive };
}
else {
options = { persistent: true };
}
return _fs.watch(
path,
{ persistent: true, recursive: !!recursive },
options,
(eventName: string, relativeFileName: string) => {
// In watchDirectory we only care about adding and removing files (when event name is
// "rename"); changes made within files are handled by corresponding fileWatchers (when
// event name is "change")
if (eventName === "rename") {
// When deleting a file, the passed baseFileName is null
callback(!relativeFileName ? relativeFileName : normalizePath(ts.combinePaths(path, relativeFileName)));
callback(!relativeFileName ? relativeFileName : normalizePath(combinePaths(path, relativeFileName)));
};
}
);
@@ -511,5 +615,3 @@ namespace ts {
}
})();
}
+4 -2
View File
@@ -334,7 +334,8 @@ namespace ts {
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
}
if (configFileName) {
configFileWatcher = sys.watchFile(configFileName, configFileChanged);
const configFilePath = toPath(configFileName, sys.getCurrentDirectory(), createGetCanonicalFileName(sys.useCaseSensitiveFileNames));
configFileWatcher = sys.watchFile(configFilePath, configFileChanged);
}
if (sys.watchDirectory && configFileName) {
const directory = ts.getDirectoryPath(configFileName);
@@ -442,7 +443,8 @@ namespace ts {
const sourceFile = hostGetSourceFile(fileName, languageVersion, onError);
if (sourceFile && compilerOptions.watch) {
// Attach a file watcher
sourceFile.fileWatcher = sys.watchFile(sourceFile.fileName, (fileName: string, removed?: boolean) => sourceFileChanged(sourceFile, removed));
const filePath = toPath(sourceFile.fileName, sys.getCurrentDirectory(), createGetCanonicalFileName(sys.useCaseSensitiveFileNames));
sourceFile.fileWatcher = sys.watchFile(filePath, (fileName: string, removed?: boolean) => sourceFileChanged(sourceFile, removed));
}
return sourceFile;
}
+2 -2
View File
@@ -1002,7 +1002,7 @@ namespace ts.server {
info.setFormatOptions(this.getFormatCodeOptions());
this.filenameToScriptInfo[fileName] = info;
if (!info.isOpen) {
info.fileWatcher = this.host.watchFile(fileName, _ => { this.watchedFileChanged(fileName); });
info.fileWatcher = this.host.watchFile(<Path>fileName, _ => { this.watchedFileChanged(fileName); });
}
}
}
@@ -1215,7 +1215,7 @@ namespace ts.server {
}
}
project.finishGraph();
project.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(project));
project.projectFileWatcher = this.host.watchFile(<Path>configFilename, _ => this.watchedProjectConfigFileChanged(project));
this.log("Add recursive watcher for: " + ts.getDirectoryPath(configFilename));
project.directoryWatcher = this.host.watchDirectory(
ts.getDirectoryPath(configFilename),
+29 -11
View File
@@ -2018,13 +2018,6 @@ namespace ts {
return createLanguageServiceSourceFile(sourceFile.fileName, scriptSnapshot, sourceFile.languageVersion, version, /*setNodeParents*/ true);
}
export function createGetCanonicalFileName(useCaseSensitivefileNames: boolean): (fileName: string) => string {
return useCaseSensitivefileNames
? ((fileName) => fileName)
: ((fileName) => fileName.toLowerCase());
}
export function createDocumentRegistry(useCaseSensitiveFileNames?: boolean, currentDirectory = ""): DocumentRegistry {
// Maps from compiler setting target (ES3, ES5, etc.) to all the cached documents we have
// for those settings.
@@ -6018,14 +6011,38 @@ namespace ts {
// Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result);
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ {});
}
});
return result;
}
function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, result: Symbol[]): void {
/**
* Find symbol of the given property-name and add the symbol to the given result array
* @param symbol a symbol to start searching for the given propertyName
* @param propertyName a name of property to serach for
* @param result an array of symbol of found property symbols
* @param previousIterationSymbolsCache a cache of symbol from previous iterations of calling this function to prevent infinite revisitng of the same symbol.
* The value of previousIterationSymbol is undefined when the function is first called.
*/
function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, result: Symbol[],
previousIterationSymbolsCache: SymbolTable): void {
// If the current symbol is the same as the previous-iteration symbol, we can just return the symbol that has already been visited
// This is particularly important for the following cases, so that we do not infinitely visit the same symbol.
// For example:
// interface C extends C {
// /*findRef*/propName: string;
// }
// The first time getPropertySymbolsFromBaseTypes is called when finding-all-references at propName,
// the symbol argument will be the symbol of an interface "C" and previousIterationSymbol is undefined,
// the function will add any found symbol of the property-name, then its sub-routine will call
// getPropertySymbolsFromBaseTypes again to walk up any base types to prevent revisiting already
// visited symbol, interface "C", the sub-routine will pass the current symbol as previousIterationSymbol.
if (hasProperty(previousIterationSymbolsCache, symbol.name)) {
return;
}
if (symbol && symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
forEach(symbol.getDeclarations(), declaration => {
if (declaration.kind === SyntaxKind.ClassDeclaration) {
@@ -6049,7 +6066,8 @@ namespace ts {
}
// Visit the typeReference as well to see if it directly or indirectly use that property
getPropertySymbolsFromBaseTypes(type.symbol, propertyName, result);
previousIterationSymbolsCache[symbol.name] = symbol;
getPropertySymbolsFromBaseTypes(type.symbol, propertyName, result, previousIterationSymbolsCache);
}
}
}
@@ -6101,7 +6119,7 @@ namespace ts {
// see if any is in the list
if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
const result: Symbol[] = [];
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result);
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ {});
return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
}