Merge branch 'master' into wip-master-statelessOverload

This commit is contained in:
Kanchalai Tanglertsampan
2017-01-31 11:33:07 -08:00
79 changed files with 3463 additions and 391 deletions
+106 -22
View File
@@ -2465,7 +2465,8 @@ namespace ts {
const symbol = type.symbol;
if (symbol) {
// Always use 'typeof T' for type of class, enum, and module objects
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
if (symbol.flags & SymbolFlags.Class && !getBaseTypeVariableOfClass(symbol) ||
symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule)) {
writeTypeOfSymbol(type, flags);
}
else if (shouldWriteTypeOfFunctionSymbol()) {
@@ -3644,6 +3645,11 @@ namespace ts {
return links.type;
}
function getBaseTypeVariableOfClass(symbol: Symbol) {
const baseConstructorType = getBaseConstructorTypeOfClass(getDeclaredTypeOfClassOrInterface(symbol));
return baseConstructorType.flags & TypeFlags.TypeVariable ? baseConstructorType : undefined;
}
function getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
const links = getSymbolLinks(symbol);
if (!links.type) {
@@ -3652,8 +3658,13 @@ namespace ts {
}
else {
const type = createObjectType(ObjectFlags.Anonymous, symbol);
links.type = strictNullChecks && symbol.flags & SymbolFlags.Optional ?
includeFalsyTypes(type, TypeFlags.Undefined) : type;
if (symbol.flags & SymbolFlags.Class) {
const baseTypeVariable = getBaseTypeVariableOfClass(symbol);
links.type = baseTypeVariable ? getIntersectionType([type, baseTypeVariable]) : type;
}
else {
links.type = strictNullChecks && symbol.flags & SymbolFlags.Optional ? includeFalsyTypes(type, TypeFlags.Undefined) : type;
}
}
}
return links.type;
@@ -3817,8 +3828,26 @@ namespace ts {
return concatenate(getOuterTypeParametersOfClassOrInterface(symbol), getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol));
}
// A type is a mixin constructor if it has a single construct signature taking no type parameters and a single
// rest parameter of type any[].
function isMixinConstructorType(type: Type) {
const signatures = getSignaturesOfType(type, SignatureKind.Construct);
if (signatures.length === 1) {
const s = signatures[0];
return !s.typeParameters && s.parameters.length === 1 && s.hasRestParameter && getTypeOfParameter(s.parameters[0]) === anyArrayType;
}
return false;
}
function isConstructorType(type: Type): boolean {
return isValidBaseType(type) && getSignaturesOfType(type, SignatureKind.Construct).length > 0;
if (isValidBaseType(type) && getSignaturesOfType(type, SignatureKind.Construct).length > 0) {
return true;
}
if (type.flags & TypeFlags.TypeVariable) {
const constraint = getBaseConstraintOfType(<TypeVariable>type);
return isValidBaseType(constraint) && isMixinConstructorType(constraint);
}
return false;
}
function getBaseTypeNodeOfClass(type: InterfaceType): ExpressionWithTypeArguments {
@@ -3897,7 +3926,7 @@ namespace ts {
function resolveBaseTypesOfClass(type: InterfaceType): void {
type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
const baseConstructorType = <ObjectType>getBaseConstructorTypeOfClass(type);
const baseConstructorType = getApparentType(getBaseConstructorTypeOfClass(type));
if (!(baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection))) {
return;
}
@@ -4547,16 +4576,47 @@ namespace ts {
getUnionType([info1.type, info2.type]), info1.isReadonly || info2.isReadonly);
}
function includeMixinType(type: Type, types: Type[], index: number): Type {
const mixedTypes: Type[] = [];
for (let i = 0; i < types.length; i++) {
if (i === index) {
mixedTypes.push(type);
}
else if (isMixinConstructorType(types[i])) {
mixedTypes.push(getReturnTypeOfSignature(getSignaturesOfType(types[i], SignatureKind.Construct)[0]));
}
}
return getIntersectionType(mixedTypes);
}
function resolveIntersectionTypeMembers(type: IntersectionType) {
// The members and properties collections are empty for intersection types. To get all properties of an
// intersection type use getPropertiesOfType (only the language service uses this).
let callSignatures: Signature[] = emptyArray;
let constructSignatures: Signature[] = emptyArray;
let stringIndexInfo: IndexInfo = undefined;
let numberIndexInfo: IndexInfo = undefined;
for (const t of type.types) {
let stringIndexInfo: IndexInfo;
let numberIndexInfo: IndexInfo;
const types = type.types;
const mixinCount = countWhere(types, isMixinConstructorType);
for (let i = 0; i < types.length; i++) {
const t = type.types[i];
// When an intersection type contains mixin constructor types, the construct signatures from
// those types are discarded and their return types are mixed into the return types of all
// other construct signatures in the intersection type. For example, the intersection type
// '{ new(...args: any[]) => A } & { new(s: string) => B }' has a single construct signature
// 'new(s: string) => A & B'.
if (mixinCount === 0 || mixinCount === types.length && i === 0 || !isMixinConstructorType(t)) {
let signatures = getSignaturesOfType(t, SignatureKind.Construct);
if (signatures.length && mixinCount > 0) {
signatures = map(signatures, s => {
const clone = cloneSignature(s);
clone.resolvedReturnType = includeMixinType(getReturnTypeOfSignature(s), types, i);
return clone;
});
}
constructSignatures = concatenate(constructSignatures, signatures);
}
callSignatures = concatenate(callSignatures, getSignaturesOfType(t, SignatureKind.Call));
constructSignatures = concatenate(constructSignatures, getSignaturesOfType(t, SignatureKind.Construct));
stringIndexInfo = intersectIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String));
numberIndexInfo = intersectIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number));
}
@@ -4598,7 +4658,7 @@ namespace ts {
constructSignatures = getDefaultConstructSignatures(classType);
}
const baseConstructorType = getBaseConstructorTypeOfClass(classType);
if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.TypeVariable)) {
members = createSymbolTable(getNamedMembers(members));
addInheritedMembers(members, getPropertiesOfType(baseConstructorType));
}
@@ -4895,6 +4955,7 @@ namespace ts {
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string): Symbol {
const types = containingType.types;
const excludeModifiers = containingType.flags & TypeFlags.Union ? ModifierFlags.Private | ModifierFlags.Protected : 0;
let props: Symbol[];
// Flags we want to propagate to the result if they exist in all source symbols
let commonFlags = (containingType.flags & TypeFlags.Intersection) ? SymbolFlags.Optional : SymbolFlags.None;
@@ -4904,7 +4965,7 @@ namespace ts {
const type = getApparentType(current);
if (type !== unknownType) {
const prop = getPropertyOfType(type, name);
if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected))) {
if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & excludeModifiers)) {
commonFlags &= prop.flags;
if (!props) {
props = [prop];
@@ -6808,6 +6869,11 @@ namespace ts {
}
}
break;
case SyntaxKind.MappedType:
if (contains(mappedTypes, getDeclaredTypeOfTypeParameter(getSymbolOfNode((<MappedTypeNode>node).typeParameter)))) {
return true;
}
break;
case SyntaxKind.JSDocFunctionType:
const func = node as JSDocFunctionType;
for (const p of func.parameters) {
@@ -6977,9 +7043,12 @@ namespace ts {
result.properties = resolved.properties;
result.callSignatures = emptyArray;
result.constructSignatures = emptyArray;
type = result;
return result;
}
}
else if (type.flags & TypeFlags.Intersection) {
return getIntersectionType(map((<IntersectionType>type).types, getTypeWithoutSignatures));
}
return type;
}
@@ -7652,7 +7721,7 @@ namespace ts {
return false;
}
function isEmptyObjectType(t: ResolvedType) {
function isEmptyResolvedType(t: ResolvedType) {
return t.properties.length === 0 &&
t.callSignatures.length === 0 &&
t.constructSignatures.length === 0 &&
@@ -7660,6 +7729,10 @@ namespace ts {
!t.numberIndexInfo;
}
function isEmptyObjectType(type: Type) {
return type.flags & TypeFlags.Object && isEmptyResolvedType(resolveStructuredTypeMembers(<ObjectType>type));
}
function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean {
if (maybeTypeOfKind(target, TypeFlags.Object) && !(getObjectFlags(target) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) {
const isComparingJsxAttributes = !!(source.flags & TypeFlags.JsxAttributes);
@@ -7881,10 +7954,14 @@ namespace ts {
}
}
}
else if ((<MappedType>target).declaration.questionToken && isEmptyObjectType(source)) {
return Ternary.True;
}
}
else if (relation !== identityRelation) {
const resolved = resolveStructuredTypeMembers(<ObjectType>target);
if (isEmptyObjectType(resolved) || resolved.stringIndexInfo && resolved.stringIndexInfo.type.flags & TypeFlags.Any) {
if (isEmptyResolvedType(resolved) || resolved.stringIndexInfo && resolved.stringIndexInfo.type.flags & TypeFlags.Any) {
return Ternary.True;
}
}
@@ -11748,7 +11825,7 @@ namespace ts {
member = prop;
}
else if (memberDecl.kind === SyntaxKind.SpreadAssignment) {
if (languageVersion < ScriptTarget.ESNext) {
if (languageVersion < ScriptTarget.ES2015) {
checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign);
}
if (propertiesArray.length > 0) {
@@ -12533,12 +12610,15 @@ namespace ts {
// - In a static member function or static member accessor
// where this references the constructor function object of a derived class,
// a super property access is permitted and must specify a public static member function of the base class.
if (languageVersion < ScriptTarget.ES2015 && getDeclarationKindFromSymbol(prop) !== SyntaxKind.MethodDeclaration) {
// `prop` refers to a *property* declared in the super class
// rather than a *method*, so it does not satisfy the above criteria.
if (languageVersion < ScriptTarget.ES2015) {
const propKind = getDeclarationKindFromSymbol(prop);
if (propKind !== SyntaxKind.MethodDeclaration && propKind !== SyntaxKind.MethodSignature) {
// `prop` refers to a *property* declared in the super class
// rather than a *method*, so it does not satisfy the above criteria.
error(errorNode, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword);
return false;
error(errorNode, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword);
return false;
}
}
if (flags & ModifierFlags.Abstract) {
@@ -18712,7 +18792,8 @@ namespace ts {
const baseTypes = getBaseTypes(type);
if (baseTypes.length && produceDiagnostics) {
const baseType = baseTypes[0];
const staticBaseType = getBaseConstructorTypeOfClass(type);
const baseConstructorType = getBaseConstructorTypeOfClass(type);
const staticBaseType = getApparentType(baseConstructorType);
checkBaseTypeAccessibility(staticBaseType, baseTypeNode);
checkSourceElement(baseTypeNode.expression);
if (baseTypeNode.typeArguments) {
@@ -18726,6 +18807,9 @@ namespace ts {
checkTypeAssignableTo(typeWithThis, getTypeWithThisArgument(baseType, type.thisType), node.name || node, Diagnostics.Class_0_incorrectly_extends_base_class_1);
checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node,
Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1);
if (baseConstructorType.flags & TypeFlags.TypeVariable && !isMixinConstructorType(staticType)) {
error(node.name || node, Diagnostics.A_mixin_class_must_have_a_constructor_with_a_single_rest_parameter_of_type_any);
}
if (baseType.symbol && baseType.symbol.valueDeclaration &&
!isInAmbientContext(baseType.symbol.valueDeclaration) &&
@@ -18735,7 +18819,7 @@ namespace ts {
}
}
if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class)) {
if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class) && !(baseConstructorType.flags & TypeFlags.TypeVariable)) {
// When the static base type is a "class-like" constructor function (but not actually a class), we verify
// that all instantiated base constructor signatures return the same type. We can simply compare the type
// references (as opposed to checking the structure of the types) because elsewhere we have already checked
-1
View File
@@ -1258,7 +1258,6 @@ namespace ts {
const literalFiles = arrayFrom(literalFileMap.values());
const wildcardFiles = arrayFrom(wildcardFileMap.values());
wildcardFiles.sort(host.useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive);
return {
fileNames: literalFiles.concat(wildcardFiles),
wildcardDirectories
+50 -36
View File
@@ -260,6 +260,16 @@ namespace ts {
return undefined;
}
/** Works like Array.prototype.findIndex, returning `-1` if no element satisfying the predicate is found. */
export function findIndex<T>(array: T[], predicate: (element: T, index: number) => boolean): number {
for (let i = 0; i < array.length; i++) {
if (predicate(array[i], i)) {
return i;
}
}
return -1;
}
/**
* Returns the first truthy result of `callback`, or else fails.
* This is like `forEach`, but never returns undefined.
@@ -1724,7 +1734,19 @@ namespace ts {
const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*";
const singleAsteriskRegexFragmentOther = "[^/]*";
export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude") {
export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude"): string | undefined {
const patterns = getRegularExpressionsForWildcards(specs, basePath, usage);
if (!patterns || !patterns.length) {
return undefined;
}
const pattern = patterns.map(pattern => `(${pattern})`).join("|");
// If excluding, match "foo/bar/baz...", but if including, only allow "foo".
const terminator = usage === "exclude" ? "($|/)" : "$";
return `^(${pattern})${terminator}`;
}
function getRegularExpressionsForWildcards(specs: string[], basePath: string, usage: "files" | "directories" | "exclude"): string[] | undefined {
if (specs === undefined || specs.length === 0) {
return undefined;
}
@@ -1738,33 +1760,8 @@ namespace ts {
*/
const doubleAsteriskRegexFragment = usage === "exclude" ? "(/.+?)?" : "(/[^/.][^/]*)*?";
let pattern = "";
let hasWrittenSubpattern = false;
for (const spec of specs) {
if (!spec) {
continue;
}
const subPattern = getSubPatternFromSpec(spec, basePath, usage, singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter);
if (subPattern === undefined) {
continue;
}
if (hasWrittenSubpattern) {
pattern += "|";
}
pattern += "(" + subPattern + ")";
hasWrittenSubpattern = true;
}
if (!pattern) {
return undefined;
}
// If excluding, match "foo/bar/baz...", but if including, only allow "foo".
const terminator = usage === "exclude" ? "($|/)" : "$";
return `^(${pattern})${terminator}`;
return flatMap(specs, spec =>
spec && getSubPatternFromSpec(spec, basePath, usage, singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter));
}
/**
@@ -1859,6 +1856,9 @@ namespace ts {
}
export interface FileMatcherPatterns {
/** One pattern for each "include" spec. */
includeFilePatterns: string[];
/** One pattern matching one of any of the "include" specs. */
includeFilePattern: string;
includeDirectoryPattern: string;
excludePattern: string;
@@ -1871,6 +1871,7 @@ namespace ts {
const absolutePath = combinePaths(currentDirectory, path);
return {
includeFilePatterns: map(getRegularExpressionsForWildcards(includes, absolutePath, "files"), pattern => `^${pattern}$`),
includeFilePattern: getRegularExpressionForWildcard(includes, absolutePath, "files"),
includeDirectoryPattern: getRegularExpressionForWildcard(includes, absolutePath, "directories"),
excludePattern: getRegularExpressionForWildcard(excludes, absolutePath, "exclude"),
@@ -1885,26 +1886,39 @@ namespace ts {
const patterns = getFileMatcherPatterns(path, excludes, includes, useCaseSensitiveFileNames, currentDirectory);
const regexFlag = useCaseSensitiveFileNames ? "" : "i";
const includeFileRegex = patterns.includeFilePattern && new RegExp(patterns.includeFilePattern, regexFlag);
const includeFileRegexes = patterns.includeFilePatterns && patterns.includeFilePatterns.map(pattern => new RegExp(pattern, regexFlag));
const includeDirectoryRegex = patterns.includeDirectoryPattern && new RegExp(patterns.includeDirectoryPattern, regexFlag);
const excludeRegex = patterns.excludePattern && new RegExp(patterns.excludePattern, regexFlag);
const result: string[] = [];
// Associate an array of results with each include regex. This keeps results in order of the "include" order.
// If there are no "includes", then just put everything in results[0].
const results: string[][] = includeFileRegexes ? includeFileRegexes.map(() => []) : [[]];
const comparer = useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive;
for (const basePath of patterns.basePaths) {
visitDirectory(basePath, combinePaths(currentDirectory, basePath));
}
return result;
return flatten(results);
function visitDirectory(path: string, absolutePath: string) {
const { files, directories } = getFileSystemEntries(path);
let { files, directories } = getFileSystemEntries(path);
files = files.slice().sort(comparer);
directories = directories.slice().sort(comparer);
for (const current of files) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if ((!extensions || fileExtensionIsAny(name, extensions)) &&
(!includeFileRegex || includeFileRegex.test(absoluteName)) &&
(!excludeRegex || !excludeRegex.test(absoluteName))) {
result.push(name);
if (extensions && !fileExtensionIsAny(name, extensions)) continue;
if (excludeRegex && excludeRegex.test(absoluteName)) continue;
if (!includeFileRegexes) {
results[0].push(name);
}
else {
const includeIndex = findIndex(includeFileRegexes, re => re.test(absoluteName));
if (includeIndex !== -1) {
results[includeIndex].push(name);
}
}
}
+8
View File
@@ -1783,6 +1783,10 @@
"category": "Error",
"code": 2544
},
"A mixin class must have a constructor with a single rest parameter of type 'any[]'.": {
"category": "Error",
"code": 2545
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600
@@ -3267,6 +3271,10 @@
"category": "Message",
"code": 90007
},
"Add 'this.' to unresolved variable.": {
"category": "Message",
"code": 90008
},
"Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig": {
"category": "Error",
"code": 90009
+4 -2
View File
@@ -1056,9 +1056,11 @@ namespace ts {
// Also emit a dot if expression is a integer const enum value - it will appear in generated code as numeric literal
function needsDotDotForPropertyAccess(expression: Expression) {
if (expression.kind === SyntaxKind.NumericLiteral) {
// check if numeric literal was originally written with a dot
// check if numeric literal is a decimal literal that was originally written with a dot
const text = getLiteralTextOfNode(<LiteralExpression>expression);
return text.indexOf(tokenToString(SyntaxKind.DotToken)) < 0;
return getNumericLiteralFlags(text, /*hint*/ NumericLiteralFlags.All) === NumericLiteralFlags.None
&& !(<LiteralExpression>expression).isOctalLiteral
&& text.indexOf(tokenToString(SyntaxKind.DotToken)) < 0;
}
else if (isPropertyAccessExpression(expression) || isElementAccessExpression(expression)) {
// check if constant enum value is integer
+7 -2
View File
@@ -6701,10 +6701,15 @@ namespace ts {
typedefTag.fullName = parseJSDocTypeNameWithNamespace(/*flags*/ 0);
if (typedefTag.fullName) {
let rightNode = typedefTag.fullName;
while (rightNode.kind !== SyntaxKind.Identifier) {
while (true) {
if (rightNode.kind === SyntaxKind.Identifier || !rightNode.body) {
// if node is identifier - use it as name
// otherwise use name of the rightmost part that we were able to parse
typedefTag.name = rightNode.kind === SyntaxKind.Identifier ? rightNode : rightNode.name;
break;
}
rightNode = rightNode.body;
}
typedefTag.name = rightNode;
}
typedefTag.typeExpression = typeExpression;
skipWhitespace();
+5
View File
@@ -402,6 +402,11 @@ namespace ts {
};
export function createAssignHelper(context: TransformationContext, attributesSegments: Expression[]) {
if (context.getCompilerOptions().target >= ScriptTarget.ES2015) {
return createCall(createPropertyAccess(createIdentifier("Object"), "assign"),
/*typeArguments*/ undefined,
attributesSegments);
}
context.requestEmitHelper(assignHelper);
return createCall(
getHelperName("__assign"),
+53 -8
View File
@@ -341,16 +341,52 @@ namespace ts {
}
export function isBinaryOrOctalIntegerLiteral(node: LiteralLikeNode, text: string) {
if (node.kind === SyntaxKind.NumericLiteral && text.length > 1) {
return node.kind === SyntaxKind.NumericLiteral
&& (getNumericLiteralFlags(text, /*hint*/ NumericLiteralFlags.BinaryOrOctal) & NumericLiteralFlags.BinaryOrOctal) !== 0;
}
export const enum NumericLiteralFlags {
None = 0,
Hexadecimal = 1 << 0,
Binary = 1 << 1,
Octal = 1 << 2,
Scientific = 1 << 3,
BinaryOrOctal = Binary | Octal,
BinaryOrOctalOrHexadecimal = BinaryOrOctal | Hexadecimal,
All = Hexadecimal | Binary | Octal | Scientific,
}
/**
* Scans a numeric literal string to determine the form of the number.
* @param text Numeric literal text
* @param hint If `Scientific` or `All` is specified, performs a more expensive check to scan for scientific notation.
*/
export function getNumericLiteralFlags(text: string, hint?: NumericLiteralFlags) {
if (text.length > 1) {
switch (text.charCodeAt(1)) {
case CharacterCodes.b:
case CharacterCodes.B:
return NumericLiteralFlags.Binary;
case CharacterCodes.o:
case CharacterCodes.O:
return true;
return NumericLiteralFlags.Octal;
case CharacterCodes.x:
case CharacterCodes.X:
return NumericLiteralFlags.Hexadecimal;
}
if (hint & NumericLiteralFlags.Scientific) {
for (let i = text.length - 1; i >= 0; i--) {
switch (text.charCodeAt(i)) {
case CharacterCodes.e:
case CharacterCodes.E:
return NumericLiteralFlags.Scientific;
}
}
}
}
return false;
return NumericLiteralFlags.None;
}
function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) {
@@ -395,7 +431,7 @@ namespace ts {
function isShorthandAmbientModule(node: Node): boolean {
// The only kind of module that can be missing a body is a shorthand ambient module.
return node.kind === SyntaxKind.ModuleDeclaration && (!(<ModuleDeclaration>node).body);
return node && node.kind === SyntaxKind.ModuleDeclaration && (!(<ModuleDeclaration>node).body);
}
export function isBlockScopedContainerTopLevel(node: Node): boolean {
@@ -1667,11 +1703,15 @@ namespace ts {
node = parent;
break;
case SyntaxKind.ShorthandPropertyAssignment:
if ((<ShorthandPropertyAssignment>parent).name !== node) {
if ((parent as ShorthandPropertyAssignment).name !== node) {
return AssignmentKind.None;
}
// Fall through
node = parent.parent;
break;
case SyntaxKind.PropertyAssignment:
if ((parent as ShorthandPropertyAssignment).name === node) {
return AssignmentKind.None;
}
node = parent.parent;
break;
default:
@@ -1683,7 +1723,8 @@ namespace ts {
// A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property
// assignment in an object literal that is an assignment target, or if it is parented by an array literal that is
// an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ p: a}] = xxx'.
// an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ a }] = xxx'.
// (Note that `p` is not a target in the above examples, only `a`.)
export function isAssignmentTarget(node: Node): boolean {
return getAssignmentTargetKind(node) !== AssignmentKind.None;
}
@@ -3109,7 +3150,11 @@ namespace ts {
}
export function getLocalSymbolForExportDefault(symbol: Symbol) {
return symbol && symbol.valueDeclaration && hasModifier(symbol.valueDeclaration, ModifierFlags.Default) ? symbol.valueDeclaration.localSymbol : undefined;
return isExportDefaultSymbol(symbol) ? symbol.valueDeclaration.localSymbol : undefined;
}
export function isExportDefaultSymbol(symbol: Symbol): boolean {
return symbol && symbol.valueDeclaration && hasModifier(symbol.valueDeclaration, ModifierFlags.Default);
}
/** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */
+41 -11
View File
@@ -346,9 +346,9 @@ namespace ts {
fileNames: [
"c:/dev/a.ts",
"c:/dev/b.ts",
"c:/dev/node_modules/a.ts",
"c:/dev/bower_components/a.ts",
"c:/dev/jspm_packages/a.ts",
"c:/dev/node_modules/a.ts"
"c:/dev/jspm_packages/a.ts"
],
wildcardDirectories: {},
};
@@ -373,9 +373,9 @@ namespace ts {
options: {},
errors: [],
fileNames: [
"c:/dev/node_modules/a.ts",
"c:/dev/bower_components/a.ts",
"c:/dev/jspm_packages/a.ts",
"c:/dev/node_modules/a.ts"
"c:/dev/jspm_packages/a.ts"
],
wildcardDirectories: {},
};
@@ -398,9 +398,9 @@ namespace ts {
fileNames: [
"c:/dev/a.ts",
"c:/dev/b.ts",
"c:/dev/node_modules/a.ts",
"c:/dev/bower_components/a.ts",
"c:/dev/jspm_packages/a.ts",
"c:/dev/node_modules/a.ts"
"c:/dev/jspm_packages/a.ts"
],
wildcardDirectories: {},
};
@@ -410,6 +410,36 @@ namespace ts {
});
describe("with wildcard include list", () => {
it("is sorted in include order, then in alphabetical order", () => {
const json = {
include: [
"z/*.ts",
"x/*.ts"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/z/a.ts",
"c:/dev/z/aba.ts",
"c:/dev/z/abz.ts",
"c:/dev/z/b.ts",
"c:/dev/z/bba.ts",
"c:/dev/z/bbz.ts",
"c:/dev/x/a.ts",
"c:/dev/x/aa.ts",
"c:/dev/x/b.ts"
],
wildcardDirectories: {
"c:/dev/z": ts.WatchDirectoryFlags.None,
"c:/dev/x": ts.WatchDirectoryFlags.None
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
});
it("same named declarations are excluded", () => {
const json = {
include: [
@@ -506,8 +536,8 @@ namespace ts {
options: {},
errors: [],
fileNames: [
"c:/dev/x/a.ts",
"c:/dev/x/y/a.ts",
"c:/dev/x/a.ts",
"c:/dev/z/a.ts"
],
wildcardDirectories: {
@@ -1282,8 +1312,8 @@ namespace ts {
options: {},
errors: [],
fileNames: [
"c:/dev/.z/.b.ts",
"c:/dev/x/.y/a.ts"
"c:/dev/x/.y/a.ts",
"c:/dev/.z/.b.ts"
],
wildcardDirectories: {}
};
@@ -1323,8 +1353,8 @@ namespace ts {
options: {},
errors: [],
fileNames: [
"c:/dev/.z/.b.ts",
"c:/dev/x/.y/a.ts"
"c:/dev/x/.y/a.ts",
"c:/dev/.z/.b.ts"
],
wildcardDirectories: {
"c:/dev/.z": ts.WatchDirectoryFlags.Recursive,
+2 -2
View File
@@ -22,7 +22,7 @@ interface ReadonlyMap<K, V> {
readonly size: number;
}
interface WeakMap<K, V> {
interface WeakMap<K extends object, V> {
delete(key: K): boolean;
get(key: K): V | undefined;
has(key: K): boolean;
@@ -31,7 +31,7 @@ interface WeakMap<K, V> {
interface WeakMapConstructor {
new (): WeakMap<any, any>;
new <K, V>(entries?: [K, V][]): WeakMap<K, V>;
new <K extends object, V>(entries?: [K, V][]): WeakMap<K, V>;
readonly prototype: WeakMap<any, any>;
}
declare var WeakMap: WeakMapConstructor;
+1 -1
View File
@@ -325,7 +325,7 @@ interface ObjectConstructor {
* @param o The object to change its prototype.
* @param proto The value of the new prototype or null.
*/
setPrototypeOf(o: any, proto: any): any;
setPrototypeOf(o: any, proto: object | null): any;
/**
* Gets the own property descriptor of the specified object.
+3 -3
View File
@@ -99,10 +99,10 @@ interface MapConstructor {
new <K, V>(iterable: Iterable<[K, V]>): Map<K, V>;
}
interface WeakMap<K, V> { }
interface WeakMap<K extends object, V> { }
interface WeakMapConstructor {
new <K, V>(iterable: Iterable<[K, V]>): WeakMap<K, V>;
new <K extends object, V>(iterable: Iterable<[K, V]>): WeakMap<K, V>;
}
interface Set<T> {
@@ -442,4 +442,4 @@ interface Float64ArrayConstructor {
* @param thisArg Value of 'this' used to invoke the mapfn.
*/
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Float64Array;
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
interface ProxyHandler<T> {
getPrototypeOf? (target: T): {} | null;
getPrototypeOf? (target: T): object | null;
setPrototypeOf? (target: T, v: any): boolean;
isExtensible? (target: T): boolean;
preventExtensions? (target: T): boolean;
@@ -12,7 +12,7 @@ interface ProxyHandler<T> {
enumerate? (target: T): PropertyKey[];
ownKeys? (target: T): PropertyKey[];
apply? (target: T, thisArg: any, argArray?: any): any;
construct? (target: T, argArray: any, newTarget?: any): {};
construct? (target: T, argArray: any, newTarget?: any): object
}
interface ProxyConstructor {
+2 -2
View File
@@ -110,7 +110,7 @@ interface Map<K, V> {
readonly [Symbol.toStringTag]: "Map";
}
interface WeakMap<K, V>{
interface WeakMap<K extends object, V>{
readonly [Symbol.toStringTag]: "WeakMap";
}
@@ -324,4 +324,4 @@ interface Float32Array {
*/
interface Float64Array {
readonly [Symbol.toStringTag]: "Float64Array";
}
}
+2 -2
View File
@@ -146,14 +146,14 @@ interface ObjectConstructor {
* Creates an object that has the specified prototype, and that optionally contains specified properties.
* @param o Object to use as a prototype. May be null
*/
create<T>(o: T): T;
create<T extends object>(o: T): T;
/**
* Creates an object that has the specified prototype, and that optionally contains specified properties.
* @param o Object to use as a prototype. May be null
* @param properties JavaScript object that contains one or more property descriptors.
*/
create(o: any, properties: PropertyDescriptorMap): any;
create(o: object | null, properties: PropertyDescriptorMap): any;
/**
* Adds a property to an object, or modifies attributes of an existing property.
@@ -0,0 +1,16 @@
/* @internal */
namespace ts.codefix {
registerCodeFix({
errorCodes: [Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0.code],
getCodeActions: (context: CodeFixContext) => {
const sourceFile = context.sourceFile;
const token = getTokenAtPosition(sourceFile, context.span.start);
const start = token.getStart(sourceFile);
return [{
description: getLocaleSpecificMessage(Diagnostics.Add_this_to_unresolved_variable),
changes: [{ fileName: sourceFile.fileName, textChanges: [{ newText: "this.", span: { start, length: 0 } }] }]
}];
}
});
}
+1 -1
View File
@@ -3,7 +3,7 @@
/// <reference path="fixClassSuperMustPrecedeThisAccess.ts" />
/// <reference path="fixConstructorForDerivedNeedSuperCall.ts" />
/// <reference path="fixExtendsInterfaceBecomesImplements.ts" />
/// <reference path="fixForgottenThisPropertyAccess.ts" />
/// <reference path='unusedIdentifierFixes.ts' />
/// <reference path='importFixes.ts' />
/// <reference path='helpers.ts' />
+1 -1
View File
@@ -17,7 +17,7 @@ namespace ts.DocumentHighlights {
}
function getSemanticDocumentHighlights(node: Node, typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch, /*findInStrings*/false, /*findInComments*/false, /*implementations*/false);
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch);
return referencedSymbols && convertReferencedSymbols(referencedSymbols);
}
+223 -174
View File
@@ -1,49 +1,27 @@
/* @internal */
namespace ts.FindAllReferences {
export function findReferencedSymbols(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFiles: SourceFile[], sourceFile: SourceFile, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] | undefined {
export function findReferencedSymbols(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFiles: SourceFile[], sourceFile: SourceFile, position: number, findInStrings: boolean, findInComments: boolean, isForRename: boolean): ReferencedSymbol[] | undefined {
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, /*implementations*/false);
return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, isForRename);
}
export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean, implementations: boolean): ReferencedSymbol[] | undefined {
export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings?: boolean, findInComments?: boolean, isForRename?: boolean, implementations?: boolean): ReferencedSymbol[] | undefined {
if (!implementations) {
if (isTypeKeyword(node.kind)) {
return getAllReferencesForKeyword(sourceFiles, node.kind, cancellationToken);
}
// Labels
if (isLabelName(node)) {
if (isJumpStatementTarget(node)) {
const labelDefinition = getTargetLabel((<BreakOrContinueStatement>node.parent), (<Identifier>node).text);
// if we have a label definition, look within its statement for references, if not, then
// the label is undefined and we have no results..
return labelDefinition && getLabelReferencesInNode(labelDefinition.parent, labelDefinition, cancellationToken);
}
else {
// it is a label definition and not a target, search within the parent labeledStatement
return getLabelReferencesInNode(node.parent, <Identifier>node, cancellationToken);
}
}
if (isThis(node)) {
return getReferencesForThisKeyword(node, sourceFiles, typeChecker, cancellationToken);
}
if (node.kind === SyntaxKind.SuperKeyword) {
return getReferencesForSuperKeyword(node, typeChecker, cancellationToken);
const special = getReferencedSymbolsSpecial(node, sourceFiles, typeChecker, cancellationToken);
if (special) {
return special;
}
}
// `getSymbolAtLocation` normally returns the symbol of the class when given the constructor keyword,
// so we have to specify that we want the constructor symbol.
const symbol = typeChecker.getSymbolAtLocation(node);
if (!implementations && !symbol && node.kind === SyntaxKind.StringLiteral) {
return getReferencesForStringLiteral(<StringLiteral>node, sourceFiles, typeChecker, cancellationToken);
}
let symbol = typeChecker.getSymbolAtLocation(node);
// Could not find a symbol e.g. unknown identifier
if (!symbol) {
if (!implementations && node.kind === SyntaxKind.StringLiteral) {
return getReferencesForStringLiteral(<StringLiteral>node, sourceFiles, typeChecker, cancellationToken);
}
// Can't have references to something that we have no symbol for.
return undefined;
}
@@ -55,9 +33,23 @@ namespace ts.FindAllReferences {
return undefined;
}
const { symbol: aliasedSymbol, shorthandModuleSymbol } = followAliases(symbol, node, typeChecker, isForRename);
symbol = aliasedSymbol;
// Build the set of symbols to search for, initially it has only the current symbol
const searchSymbols = populateSearchSymbolSet(symbol, node, typeChecker, implementations);
if (shorthandModuleSymbol) {
searchSymbols.push(shorthandModuleSymbol);
}
// Compute the meaning from the location and the symbol it references
const searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), declarations);
const result: ReferencedSymbol[] = [];
// Maps from a symbol ID to the ReferencedSymbol entry in 'result'.
const symbolToIndex: number[] = [];
const inheritsFromCache: Map<boolean> = createMap<boolean>();
// Get the text to search for.
// Note: if this is an external module symbol, the name doesn't include quotes.
const declaredName = stripQuotes(getDeclaredName(typeChecker, symbol, node));
@@ -65,33 +57,107 @@ namespace ts.FindAllReferences {
// Try to get the smallest valid scope that we can limit our search to;
// otherwise we'll need to search globally (i.e. include each file).
const scope = getSymbolScope(symbol);
// Maps from a symbol ID to the ReferencedSymbol entry in 'result'.
const symbolToIndex: number[] = [];
let result: ReferencedSymbol[];
if (scope) {
result = [];
getReferencesInNode(scope, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex, implementations, typeChecker, cancellationToken);
getRefs(scope, declaredName);
}
else {
const internedName = getInternedName(symbol, node);
const isDefault = isExportDefaultSymbol(symbol);
const internedName = isDefault ? symbol.valueDeclaration.localSymbol.name : getInternedName(symbol, node);
for (const sourceFile of sourceFiles) {
cancellationToken.throwIfCancellationRequested();
if (sourceFileHasName(sourceFile, internedName)) {
result = result || [];
getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex, implementations, typeChecker, cancellationToken);
const searchName = (isDefault ? getDefaultImportName(symbol, sourceFile, typeChecker) : undefined) ||
(sourceFileHasName(sourceFile, internedName) ? declaredName : undefined);
if (searchName !== undefined) {
getRefs(sourceFile, searchName);
}
}
}
return result;
function getRefs(scope: ts.Node, searchName: string): void {
getReferencesInNode(scope, symbol, searchName, node, searchMeaning, findInStrings, findInComments, result,
symbolToIndex, implementations, typeChecker, cancellationToken, searchSymbols, inheritsFromCache);
}
}
/** getReferencedSymbols for special node kinds. */
function getReferencedSymbolsSpecial(node: Node, sourceFiles: SourceFile[], typeChecker: TypeChecker, cancellationToken: CancellationToken): ReferencedSymbol[] | undefined {
if (isTypeKeyword(node.kind)) {
return getAllReferencesForKeyword(sourceFiles, node.kind, cancellationToken);
}
// Labels
if (isLabelName(node)) {
if (isJumpStatementTarget(node)) {
const labelDefinition = getTargetLabel((<BreakOrContinueStatement>node.parent), (<Identifier>node).text);
// if we have a label definition, look within its statement for references, if not, then
// the label is undefined and we have no results..
return labelDefinition && getLabelReferencesInNode(labelDefinition.parent, labelDefinition, cancellationToken);
}
else {
// it is a label definition and not a target, search within the parent labeledStatement
return getLabelReferencesInNode(node.parent, <Identifier>node, cancellationToken);
}
}
if (isThis(node)) {
return getReferencesForThisKeyword(node, sourceFiles, typeChecker, cancellationToken);
}
if (node.kind === SyntaxKind.SuperKeyword) {
return getReferencesForSuperKeyword(node, typeChecker, cancellationToken);
}
return undefined;
}
/**
* Follows aliases to get to the original declaration of a symbol.
* For a shorthand ambient module, we don't follow the alias to it, but we will need to add it to the set of search symbols.
*/
function followAliases(symbol: Symbol, node: Node, typeChecker: TypeChecker, isForRename: boolean): { symbol: Symbol, shorthandModuleSymbol?: Symbol } {
while (true) {
// When renaming a default import, only rename in the current file
if (isForRename && isImportDefaultSymbol(symbol)) {
return { symbol };
}
const aliasedSymbol = getAliasSymbolForPropertyNameSymbol(symbol, node, typeChecker);
// Don't follow alias if it goes to unknown symbol. This can happen if it points to an untyped module.
if (!aliasedSymbol || !aliasedSymbol.declarations) {
return { symbol };
}
if (ts.isShorthandAmbientModuleSymbol(aliasedSymbol)) {
return { symbol, shorthandModuleSymbol: aliasedSymbol };
}
symbol = aliasedSymbol;
}
}
function sourceFileHasName(sourceFile: SourceFile, name: string): boolean {
return getNameTable(sourceFile).get(name) !== undefined;
}
/**
* Given a symbol, see if any of the imports in a source file reference it.
* Only call this if `symbol` is a default export.
*/
function getDefaultImportName(symbol: Symbol, sourceFile: SourceFile, checker: ts.TypeChecker): string | undefined {
for (const importSpecifier of sourceFile.imports) {
const importDecl = importSpecifier.parent as ts.ImportDeclaration;
Debug.assert(importDecl.moduleSpecifier === importSpecifier);
const defaultName = importDecl.importClause.name;
const defaultReferencedSymbol = checker.getAliasedSymbol(checker.getSymbolAtLocation(defaultName));
if (symbol === defaultReferencedSymbol) {
return defaultName.text;
}
}
return undefined;
}
function getDefinition(symbol: Symbol, node: Node, typeChecker: TypeChecker): ReferencedSymbolDefinitionInfo {
const { displayParts, symbolKind } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, node.getSourceFile(), getContainerNode(node), node);
const name = displayParts.map(p => p.text).join("");
@@ -112,29 +178,30 @@ namespace ts.FindAllReferences {
}
function getAliasSymbolForPropertyNameSymbol(symbol: Symbol, location: Node, typeChecker: TypeChecker): Symbol | undefined {
if (symbol.flags & SymbolFlags.Alias) {
// Default import get alias
const defaultImport = getDeclarationOfKind(symbol, SyntaxKind.ImportClause);
if (defaultImport) {
return typeChecker.getAliasedSymbol(symbol);
}
if (!(symbol.flags & SymbolFlags.Alias)) {
return undefined;
}
const importOrExportSpecifier = <ImportOrExportSpecifier>forEach(symbol.declarations,
declaration => (declaration.kind === SyntaxKind.ImportSpecifier ||
declaration.kind === SyntaxKind.ExportSpecifier) ? declaration : undefined);
if (importOrExportSpecifier &&
// export { a }
(!importOrExportSpecifier.propertyName ||
// export {a as class } where a is location
importOrExportSpecifier.propertyName === location)) {
// If Import specifier -> get alias
// else Export specifier -> get local target
return importOrExportSpecifier.kind === SyntaxKind.ImportSpecifier ?
typeChecker.getAliasedSymbol(symbol) :
typeChecker.getExportSpecifierLocalTargetSymbol(importOrExportSpecifier);
}
// Default import get alias
const defaultImport = getDeclarationOfKind(symbol, SyntaxKind.ImportClause);
if (defaultImport) {
return typeChecker.getAliasedSymbol(symbol);
}
const importOrExportSpecifier = <ImportOrExportSpecifier>forEach(symbol.declarations,
declaration => (declaration.kind === SyntaxKind.ImportSpecifier ||
declaration.kind === SyntaxKind.ExportSpecifier) ? declaration : undefined);
if (importOrExportSpecifier &&
// export { a }
(!importOrExportSpecifier.propertyName ||
// export {a as class } where a is location
importOrExportSpecifier.propertyName === location)) {
// If Import specifier -> get alias
// else Export specifier -> get local target
return importOrExportSpecifier.kind === SyntaxKind.ImportSpecifier ?
typeChecker.getAliasedSymbol(symbol) :
typeChecker.getExportSpecifierLocalTargetSymbol(importOrExportSpecifier);
}
return undefined;
}
function followAliasIfNecessary(symbol: Symbol, location: Node, typeChecker: TypeChecker): Symbol {
@@ -166,14 +233,9 @@ namespace ts.FindAllReferences {
// If this is an export or import specifier it could have been renamed using the 'as' syntax.
// If so we want to search for whatever under the cursor.
if (isImportOrExportSpecifierName(location)) {
return location.getText();
return location.text;
}
// Try to get the local symbol if we're dealing with an 'export default'
// since that symbol has the "true" name.
const localExportDefaultSymbol = getLocalSymbolForExportDefault(symbol);
symbol = localExportDefaultSymbol || symbol;
return stripQuotes(symbol.name);
}
@@ -390,7 +452,9 @@ namespace ts.FindAllReferences {
symbolToIndex: number[],
implementations: boolean,
typeChecker: TypeChecker,
cancellationToken: CancellationToken): void {
cancellationToken: CancellationToken,
searchSymbols: Symbol[],
inheritsFromCache: Map<boolean>): void {
const sourceFile = container.getSourceFile();
@@ -398,9 +462,6 @@ namespace ts.FindAllReferences {
const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, searchText, start, container.getEnd(), cancellationToken);
const parents = getParentSymbolsOfPropertyAccess();
const inheritsFromCache: Map<boolean> = createMap<boolean>();
// Build the set of symbols to search for, initially it has only the current symbol
const searchSymbols = populateSearchSymbolSet(searchSymbol, searchLocation, typeChecker, implementations);
for (const position of possiblePositions) {
cancellationToken.throwIfCancellationRequested();
@@ -445,12 +506,12 @@ namespace ts.FindAllReferences {
addReferenceToRelatedSymbol(referenceLocation, relatedSymbol);
}
/* Because in short-hand property assignment, an identifier which stored as name of the short-hand property assignment
* has two meaning : property name and property value. Therefore when we do findAllReference at the position where
* an identifier is declared, the language service should return the position of the variable declaration as well as
* the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the
* position of property accessing, the referenceEntry of such position will be handled in the first case.
*/
else if (!(referenceSymbol.flags & SymbolFlags.Transient) && searchSymbols.indexOf(shorthandValueSymbol) >= 0) {
* has two meanings: property name and property value. Therefore when we do findAllReference at the position where
* an identifier is declared, the language service should return the position of the variable declaration as well as
* the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the
* position of property accessing, the referenceEntry of such position will be handled in the first case.
*/
else if (!(referenceSymbol.flags & SymbolFlags.Transient) && contains(searchSymbols, shorthandValueSymbol)) {
addReferenceToRelatedSymbol(referenceSymbolDeclaration.name, shorthandValueSymbol);
}
else if (searchLocation.kind === SyntaxKind.ConstructorKeyword) {
@@ -461,10 +522,10 @@ namespace ts.FindAllReferences {
return;
/* If we are just looking for implementations and this is a property access expression, we need to get the
* symbol of the local type of the symbol the property is being accessed on. This is because our search
* symbol may have a different parent symbol if the local type's symbol does not declare the property
* being accessed (i.e. it is declared in some parent class or interface)
*/
* symbol of the local type of the symbol the property is being accessed on. This is because our search
* symbol may have a different parent symbol if the local type's symbol does not declare the property
* being accessed (i.e. it is declared in some parent class or interface)
*/
function getParentSymbolsOfPropertyAccess(): Symbol[] | undefined {
if (implementations) {
const propertyAccessExpression = getPropertyAccessExpressionFromRightHandSide(searchLocation);
@@ -482,10 +543,6 @@ namespace ts.FindAllReferences {
}
}
function getPropertyAccessExpressionFromRightHandSide(node: Node): PropertyAccessExpression {
return isRightSideOfPropertyAccess(node) && <PropertyAccessExpression>node.parent;
}
/** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses. */
function findAdditionalConstructorReferences(referenceSymbol: Symbol, referenceLocation: Node): void {
Debug.assert(isClassLike(searchSymbol.valueDeclaration));
@@ -494,7 +551,7 @@ namespace ts.FindAllReferences {
if (referenceSymbol === searchSymbol && isClassLike(referenceClass)) {
Debug.assert(referenceClass.name === referenceLocation);
// This is the class declaration containing the constructor.
addReferences(findOwnConstructorCalls(searchSymbol));
addReferences(findOwnConstructorCalls(searchSymbol, sourceFile));
}
else {
// If this class appears in `extends C`, then the extending class' "super" calls are references.
@@ -512,58 +569,6 @@ namespace ts.FindAllReferences {
}
}
/** `classSymbol` is the class where the constructor was defined.
* Reference the constructor and all calls to `new this()`.
*/
function findOwnConstructorCalls(classSymbol: Symbol): Node[] {
const result: Node[] = [];
for (const decl of classSymbol.members.get("__constructor").declarations) {
const ctrKeyword = ts.findChildOfKind(decl, ts.SyntaxKind.ConstructorKeyword, sourceFile)!
Debug.assert(decl.kind === SyntaxKind.Constructor && !!ctrKeyword);
result.push(ctrKeyword);
}
classSymbol.exports.forEach(member => {
const decl = member.valueDeclaration;
if (decl && decl.kind === SyntaxKind.MethodDeclaration) {
const body = (<MethodDeclaration>decl).body;
if (body) {
forEachDescendantOfKind(body, SyntaxKind.ThisKeyword, thisKeyword => {
if (isNewExpressionTarget(thisKeyword)) {
result.push(thisKeyword);
}
});
}
}
});
return result;
}
/** Find references to `super` in the constructor of an extending class. */
function superConstructorAccesses(cls: ClassLikeDeclaration): Node[] {
const symbol = cls.symbol;
const ctr = symbol.members.get("__constructor");
if (!ctr) {
return [];
}
const result: Node[] = [];
for (const decl of ctr.declarations) {
Debug.assert(decl.kind === SyntaxKind.Constructor);
const body = (<ConstructorDeclaration>decl).body;
if (body) {
forEachDescendantOfKind(body, SyntaxKind.SuperKeyword, node => {
if (isCallExpressionTarget(node)) {
result.push(node);
}
});
}
};
return result;
}
function getReferencedSymbol(symbol: Symbol): ReferencedSymbol {
const symbolId = getSymbolId(symbol);
let index = symbolToIndex[symbolId];
@@ -591,6 +596,62 @@ namespace ts.FindAllReferences {
}
}
function getPropertyAccessExpressionFromRightHandSide(node: Node): PropertyAccessExpression {
return isRightSideOfPropertyAccess(node) && <PropertyAccessExpression>node.parent;
}
/** `classSymbol` is the class where the constructor was defined.
* Reference the constructor and all calls to `new this()`.
*/
function findOwnConstructorCalls(classSymbol: Symbol, sourceFile: SourceFile): Node[] {
const result: Node[] = [];
for (const decl of classSymbol.members.get("__constructor").declarations) {
const ctrKeyword = ts.findChildOfKind(decl, ts.SyntaxKind.ConstructorKeyword, sourceFile)!
Debug.assert(decl.kind === SyntaxKind.Constructor && !!ctrKeyword);
result.push(ctrKeyword);
}
classSymbol.exports.forEach(member => {
const decl = member.valueDeclaration;
if (decl && decl.kind === SyntaxKind.MethodDeclaration) {
const body = (<MethodDeclaration>decl).body;
if (body) {
forEachDescendantOfKind(body, SyntaxKind.ThisKeyword, thisKeyword => {
if (isNewExpressionTarget(thisKeyword)) {
result.push(thisKeyword);
}
});
}
}
});
return result;
}
/** Find references to `super` in the constructor of an extending class. */
function superConstructorAccesses(cls: ClassLikeDeclaration): Node[] {
const symbol = cls.symbol;
const ctr = symbol.members.get("__constructor");
if (!ctr) {
return [];
}
const result: Node[] = [];
for (const decl of ctr.declarations) {
Debug.assert(decl.kind === SyntaxKind.Constructor);
const body = (<ConstructorDeclaration>decl).body;
if (body) {
forEachDescendantOfKind(body, SyntaxKind.SuperKeyword, node => {
if (isCallExpressionTarget(node)) {
result.push(node);
}
});
}
};
return result;
}
function getImplementationReferenceEntryForNode(refNode: Node, result: ReferenceEntry[], typeChecker: TypeChecker): void {
// Check if we found a function/propertyAssignment/method with an implementation or initializer
if (isDeclarationName(refNode) && isImplementation(refNode.parent)) {
@@ -805,13 +866,13 @@ namespace ts.FindAllReferences {
const sourceFile = searchSpaceNode.getSourceFile();
const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "super", searchSpaceNode.getStart(), searchSpaceNode.getEnd(), cancellationToken);
forEach(possiblePositions, position => {
for (const position of possiblePositions) {
cancellationToken.throwIfCancellationRequested();
const node = getTouchingWord(sourceFile, position);
if (!node || node.kind !== SyntaxKind.SuperKeyword) {
return;
continue;
}
const container = getSuperContainer(node, /*stopOnFunctions*/ false);
@@ -822,7 +883,7 @@ namespace ts.FindAllReferences {
if (container && (ModifierFlags.Static & getModifierFlags(container)) === staticFlag && container.parent.symbol === searchSpaceNode.symbol) {
references.push(getReferenceEntryFromNode(node));
}
});
}
const definition = getDefinition(searchSpaceNode.symbol, superKeyword, typeChecker);
return [{ definition, references }];
@@ -985,7 +1046,7 @@ namespace ts.FindAllReferences {
function populateSearchSymbolSet(symbol: Symbol, location: Node, typeChecker: TypeChecker, implementations: boolean): Symbol[] {
// The search set contains at least the current symbol
let result = [symbol];
const result = [symbol];
// If the location is name of property symbol from object literal destructuring pattern
// Search the property symbol
@@ -998,22 +1059,6 @@ namespace ts.FindAllReferences {
}
}
// If the symbol is an alias, add what it aliases to the list
// import {a} from "mod";
// export {a}
// If the symbol is an alias to default declaration, add what it aliases to the list
// declare "mod" { export default class B { } }
// import B from "mod";
//// For export specifiers, the exported name can be referring to a local symbol, e.g.:
//// import {a} from "mod";
//// export {a as somethingElse}
//// We want the *local* declaration of 'a' as declared in the import,
//// *not* as declared within "mod" (or farther)
const aliasSymbol = getAliasSymbolForPropertyNameSymbol(symbol, location, typeChecker);
if (aliasSymbol) {
result = result.concat(populateSearchSymbolSet(aliasSymbol, location, typeChecker, implementations));
}
// If the location is in a context sensitive location (i.e. in an object literal) try
// to get a contextual type for it, and add the property symbol from the contextual
// type to the search set
@@ -1045,7 +1090,7 @@ namespace ts.FindAllReferences {
// Property Declaration symbol is a member of the class, so the symbol is stored in its class Declaration.symbol.members
if (symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.Parameter &&
isParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration)) {
result = result.concat(typeChecker.getSymbolsOfParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration, symbol.name));
addRange(result, typeChecker.getSymbolsOfParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration, symbol.name));
}
// If this is symbol of binding element without propertyName declaration in Object binding pattern
@@ -1057,7 +1102,7 @@ namespace ts.FindAllReferences {
// If this is a union property, add all the symbols from all its source symbols in all unioned types.
// If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list
forEach(typeChecker.getRootSymbols(symbol), rootSymbol => {
for (const rootSymbol of typeChecker.getRootSymbols(symbol)) {
if (rootSymbol !== symbol) {
result.push(rootSymbol);
}
@@ -1066,7 +1111,7 @@ namespace ts.FindAllReferences {
if (!implementations && rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap<Symbol>(), typeChecker);
}
});
}
return result;
}
@@ -1130,10 +1175,10 @@ namespace ts.FindAllReferences {
}
}
function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node, searchLocationIsConstructor: boolean, parents: Symbol[] | undefined, cache: Map<boolean>, typeChecker: TypeChecker): Symbol {
function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node, searchLocationIsConstructor: boolean, parents: Symbol[] | undefined, cache: Map<boolean>, typeChecker: TypeChecker): Symbol | undefined {
if (contains(searchSymbols, referenceSymbol)) {
// If we are searching for constructor uses, they must be 'new' expressions.
return (!searchLocationIsConstructor || isNewExpressionTarget(referenceLocation)) && referenceSymbol;
return (!searchLocationIsConstructor || isNewExpressionTarget(referenceLocation)) ? referenceSymbol : undefined;
}
// If the reference symbol is an alias, check if what it is aliasing is one of the search
@@ -1148,9 +1193,8 @@ namespace ts.FindAllReferences {
// compare to our searchSymbol
const containingObjectLiteralElement = getContainingObjectLiteralElement(referenceLocation);
if (containingObjectLiteralElement) {
const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement, typeChecker), contextualSymbol => {
return forEach(typeChecker.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
});
const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement, typeChecker), contextualSymbol =>
find(typeChecker.getRootSymbols(contextualSymbol), symbol => contains(searchSymbols, symbol)));
if (contextualSymbol) {
return contextualSymbol;
@@ -1161,7 +1205,7 @@ namespace ts.FindAllReferences {
// In below eg. get 'property' from type of elems iterating type
// for ( { property: p2 } of elems) { }
const propertySymbol = getPropertySymbolOfDestructuringAssignment(referenceLocation, typeChecker);
if (propertySymbol && searchSymbols.indexOf(propertySymbol) >= 0) {
if (propertySymbol && contains(searchSymbols, propertySymbol)) {
return propertySymbol;
}
}
@@ -1170,7 +1214,7 @@ namespace ts.FindAllReferences {
// then include the binding element in the related symbols
// let { a } : { a };
const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol, typeChecker);
if (bindingElementPropertySymbol && searchSymbols.indexOf(bindingElementPropertySymbol) >= 0) {
if (bindingElementPropertySymbol && contains(searchSymbols, bindingElementPropertySymbol)) {
return bindingElementPropertySymbol;
}
@@ -1178,7 +1222,7 @@ namespace ts.FindAllReferences {
// Or a union property, use its underlying unioned symbols
return forEach(typeChecker.getRootSymbols(referenceSymbol), rootSymbol => {
// if it is in the list, then we are done
if (searchSymbols.indexOf(rootSymbol) >= 0) {
if (contains(searchSymbols, rootSymbol)) {
return rootSymbol;
}
@@ -1195,7 +1239,7 @@ namespace ts.FindAllReferences {
const result: Symbol[] = [];
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap<Symbol>(), typeChecker);
return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
return find(result, symbol => contains(searchSymbols, symbol));
}
return undefined;
@@ -1214,7 +1258,8 @@ namespace ts.FindAllReferences {
return (<Identifier | LiteralExpression>node.name).text;
}
function getPropertySymbolsFromContextualType(node: ObjectLiteralElement, typeChecker: TypeChecker): Symbol[] {
/** Gets all symbols for one property. Does not get symbols for every property. */
function getPropertySymbolsFromContextualType(node: ObjectLiteralElement, typeChecker: TypeChecker): Symbol[] | undefined {
const objectLiteral = <ObjectLiteralExpression>node.parent;
const contextualType = typeChecker.getContextualType(objectLiteral);
const name = getNameFromObjectLiteralElement(node);
@@ -1391,4 +1436,8 @@ namespace ts.FindAllReferences {
return false;
}
function isImportDefaultSymbol(symbol: Symbol): boolean {
return symbol.declarations[0].kind === SyntaxKind.ImportClause;
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ namespace ts.GoToImplementation {
else {
// Perform "Find all References" and retrieve only those that are implementations
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken,
node, sourceFiles, /*findInStrings*/false, /*findInComments*/false, /*implementations*/true);
node, sourceFiles, /*findInStrings*/false, /*findInComments*/false, /*isForRename*/false, /*implementations*/true);
const result = flatMap(referencedSymbols, symbol =>
map(symbol.references, ({ textSpan, fileName }) => ({ textSpan, fileName })));
+5 -5
View File
@@ -1404,25 +1404,25 @@ namespace ts {
}
function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] {
const referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments);
const referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments, /*isForRename*/true);
return FindAllReferences.convertReferences(referencedSymbols);
}
function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] {
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false);
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false);
return FindAllReferences.convertReferences(referencedSymbols);
}
function findReferences(fileName: string, position: number): ReferencedSymbol[] {
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false);
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false);
// Only include referenced symbols that have a valid definition.
return filter(referencedSymbols, rs => !!rs.definition);
}
function findReferencedSymbols(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] {
function findReferencedSymbols(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, isForRename: boolean): ReferencedSymbol[] {
synchronizeHostData();
return FindAllReferences.findReferencedSymbols(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position, findInStrings, findInComments);
return FindAllReferences.findReferencedSymbols(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position, findInStrings, findInComments, isForRename);
}
/// NavigateTo
+4 -7
View File
@@ -385,7 +385,10 @@ namespace ts {
if (settingsJson == null || settingsJson == "") {
throw Error("LanguageServiceShimHostAdapter.getCompilationSettings: empty compilationSettings");
}
return <CompilerOptions>JSON.parse(settingsJson);
const compilerOptions = <CompilerOptions>JSON.parse(settingsJson);
// permit language service to handle all files (filtering should be performed on the host side)
compilerOptions.allowNonTsExtensions = true;
return compilerOptions;
}
public getScriptFileNames(): string[] {
@@ -1061,12 +1064,6 @@ namespace ts {
const compilerOptions = <CompilerOptions>JSON.parse(compilerOptionsJson);
const result = resolveModuleName(moduleName, normalizeSlashes(fileName), compilerOptions, this.host);
const resolvedFileName = result.resolvedModule ? result.resolvedModule.resolvedFileName : undefined;
if (resolvedFileName && !compilerOptions.allowJs && fileExtensionIs(resolvedFileName, ".js")) {
return {
resolvedFileName: undefined,
failedLookupLocations: []
};
}
return {
resolvedFileName,
failedLookupLocations: result.failedLookupLocations
+1
View File
@@ -83,6 +83,7 @@
"codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
"codefixes/fixClassSuperMustPrecedeThisAccess.ts",
"codefixes/fixConstructorForDerivedNeedSuperCall.ts",
"codefixes/fixForgottenThisPropertyAccess.ts",
"codefixes/fixes.ts",
"codefixes/helpers.ts",
"codefixes/importFixes.ts",
+1 -1
View File
@@ -1320,7 +1320,7 @@ namespace ts {
return name;
}
export function isImportOrExportSpecifierName(location: Node): boolean {
export function isImportOrExportSpecifierName(location: Node): location is Identifier {
return location.parent &&
(location.parent.kind === SyntaxKind.ImportSpecifier || location.parent.kind === SyntaxKind.ExportSpecifier) &&
(<ImportOrExportSpecifier>location.parent).propertyName === location;