Move reporting to checkObjectLiteral and checkJsxOpeningLikeElementOrOpeningFragment
It is now obvious that this only works when there's a contextual type for the object literal.
This commit is contained in:
parent
52a175bd6d
commit
a9d808bd0d
|
@ -17019,7 +17019,7 @@ namespace ts {
|
|||
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
|
||||
errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined
|
||||
): boolean {
|
||||
if (isTypeRelatedTo(source, target, relation, /*reportDeprecatedProperties*/ true)) return true;
|
||||
if (isTypeRelatedTo(source, target, relation)) return true;
|
||||
if (!errorNode || !elaborateError(expr, source, target, relation, headMessage, containingMessageChain, errorOutputContainer)) {
|
||||
return checkTypeRelatedTo(source, target, relation, errorNode, headMessage, containingMessageChain, errorOutputContainer);
|
||||
}
|
||||
|
@ -17788,7 +17788,7 @@ namespace ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
function isTypeRelatedTo(source: Type, target: Type, relation: ESMap<string, RelationComparisonResult>, reportDeprecatedProperties?: boolean) {
|
||||
function isTypeRelatedTo(source: Type, target: Type, relation: ESMap<string, RelationComparisonResult>) {
|
||||
if (isFreshLiteralType(source)) {
|
||||
source = (source as FreshableType).regularType;
|
||||
}
|
||||
|
@ -17815,8 +17815,7 @@ namespace ts {
|
|||
}
|
||||
if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) {
|
||||
return checkTypeRelatedTo(source, target, relation,
|
||||
/*errorNode*/ undefined, /*headMessage*/ undefined, /*containingMessageChain*/ undefined, /*errorOutputContainer*/ undefined,
|
||||
reportDeprecatedProperties);
|
||||
/*errorNode*/ undefined, /*headMessage*/ undefined, /*containingMessageChain*/ undefined, /*errorOutputContainer*/ undefined);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -17850,7 +17849,6 @@ namespace ts {
|
|||
* @param headMessage If the error chain should be prepended by a head message, then headMessage will be used.
|
||||
* @param containingMessageChain A chain of errors to prepend any new errors found.
|
||||
* @param errorOutputContainer Return the diagnostic. Do not log if 'skipLogging' is truthy.
|
||||
* @param reportDeprecatedProperties Properties with deprecated annotation will be reported, if result is true.
|
||||
*/
|
||||
function checkTypeRelatedTo(
|
||||
source: Type,
|
||||
|
@ -17860,7 +17858,6 @@ namespace ts {
|
|||
headMessage?: DiagnosticMessage,
|
||||
containingMessageChain?: () => DiagnosticMessageChain | undefined,
|
||||
errorOutputContainer?: { errors?: Diagnostic[], skipLogging?: boolean },
|
||||
reportDeprecatedProperties?: boolean
|
||||
): boolean {
|
||||
|
||||
let errorInfo: DiagnosticMessageChain | undefined;
|
||||
|
@ -17877,7 +17874,6 @@ namespace ts {
|
|||
let lastSkippedInfo: [Type, Type] | undefined;
|
||||
let incompatibleStack: [DiagnosticMessage, (string | number)?, (string | number)?, (string | number)?, (string | number)?][] = [];
|
||||
let inPropertyCheck = false;
|
||||
const deprecatedSuggestions: Parameters<typeof addDeprecatedSuggestion>[] = [];
|
||||
|
||||
Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking");
|
||||
|
||||
|
@ -17929,15 +17925,7 @@ namespace ts {
|
|||
Debug.assert(!!errorOutputContainer.errors, "missed opportunity to interact with error.");
|
||||
}
|
||||
|
||||
const isRelated = result !== Ternary.False;
|
||||
|
||||
if (isRelated) {
|
||||
for (const args of deprecatedSuggestions) {
|
||||
addDeprecatedSuggestion(...args);
|
||||
}
|
||||
}
|
||||
|
||||
return isRelated;
|
||||
return result !== Ternary.False;
|
||||
|
||||
function resetErrorInfo(saved: ReturnType<typeof captureErrorCalculationState>) {
|
||||
errorInfo = saved.errorInfo;
|
||||
|
@ -18271,9 +18259,6 @@ namespace ts {
|
|||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
if (reportDeprecatedProperties) {
|
||||
checkDeprecatedProperties(source as FreshObjectLiteralType, target);
|
||||
}
|
||||
}
|
||||
|
||||
const isPerformingCommonPropertyChecks = relation !== comparableRelation && !(intersectionState & IntersectionState.Target) &&
|
||||
|
@ -18550,27 +18535,6 @@ namespace ts {
|
|||
return prop.valueDeclaration && container.valueDeclaration && prop.valueDeclaration.parent === container.valueDeclaration;
|
||||
}
|
||||
|
||||
function checkDeprecatedProperties(source: FreshObjectLiteralType, target: Type) {
|
||||
if (!isExcessPropertyCheckTarget(target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const prop of getPropertiesOfType(source)) {
|
||||
if (!shouldCheckAsExcessProperty(prop, source.symbol)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const symbol = getPropertyOfObjectType(target, prop.escapedName);
|
||||
if (symbol?.declarations?.some(decl => decl.flags & NodeFlags.Deprecated)) {
|
||||
const node = prop.valueDeclaration!;
|
||||
const nameNode = isPropertyAssignment(node) || isShorthandPropertyAssignment(node) || isObjectLiteralMethod(node) || isJsxAttribute(node)
|
||||
? node.name
|
||||
: prop.valueDeclaration!;
|
||||
deprecatedSuggestions.push([nameNode, symbol.declarations, prop.escapedName as string]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType): Ternary {
|
||||
let result = Ternary.True;
|
||||
const sourceTypes = source.types;
|
||||
|
@ -27170,6 +27134,17 @@ namespace ts {
|
|||
symbolToString(member), typeToString(contextualType));
|
||||
}
|
||||
}
|
||||
if (contextualType) {
|
||||
const contextualProperty = getPropertyOfType(contextualType, member.escapedName)
|
||||
const isFromOverload = contextualProperty?.declarations?.some(decl => {
|
||||
const param = findAncestor(decl, isParameter)
|
||||
return param && isFunctionDeclaration(param.parent) && countWhere(getSymbolOfNode(param.parent).declarations, isFunctionLike) > 1
|
||||
})
|
||||
if (!isFromOverload) {
|
||||
checkDeprecatedProperty(member, contextualProperty)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
prop.declarations = member.declarations;
|
||||
prop.parent = member.parent;
|
||||
|
@ -27881,10 +27856,17 @@ namespace ts {
|
|||
}
|
||||
|
||||
if (isNodeOpeningLikeElement) {
|
||||
const jsxOpeningLikeNode = node as JsxOpeningLikeElement;
|
||||
const sig = getResolvedSignature(jsxOpeningLikeNode);
|
||||
checkDeprecatedSignature(sig, node as JsxOpeningLikeElement);
|
||||
checkJsxReturnAssignableToAppropriateBound(getJsxReferenceKind(jsxOpeningLikeNode), getReturnTypeOfSignature(sig), jsxOpeningLikeNode);
|
||||
const sig = getResolvedSignature(node);
|
||||
checkDeprecatedSignature(sig, node);
|
||||
const param = sig.parameters[0]
|
||||
for (const source of node.attributes.properties) {
|
||||
const member = source.symbol;
|
||||
const attributesTarget = getTypeOfSymbol(param)
|
||||
if (member && attributesTarget) {
|
||||
checkDeprecatedProperty(member, getPropertyOfType(attributesTarget, member.escapedName))
|
||||
}
|
||||
}
|
||||
checkJsxReturnAssignableToAppropriateBound(getJsxReferenceKind(node), getReturnTypeOfSignature(sig), node);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31108,6 +31090,16 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function checkDeprecatedProperty(source: Symbol, target: Symbol | undefined) {
|
||||
if (target?.declarations?.some(decl => decl.flags & NodeFlags.Deprecated)) {
|
||||
const node = source.valueDeclaration!;
|
||||
const nameNode = isPropertyAssignment(node) || isShorthandPropertyAssignment(node) || isObjectLiteralMethod(node) || isJsxAttribute(node)
|
||||
? node.name
|
||||
: source.valueDeclaration!;
|
||||
addDeprecatedSuggestion(nameNode, target.declarations, source.escapedName as string);
|
||||
}
|
||||
}
|
||||
|
||||
function getDeprecatedSuggestionNode(node: Node): Node {
|
||||
node = skipParentheses(node);
|
||||
switch (node.kind) {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
//// props = { bar, [|callback|]() {} };
|
||||
|
||||
//// // Skip if there is a type incompatibility error.
|
||||
//// const props5: Props = { foo: "foo", boo: "boo" };
|
||||
//// const props5: Props = { [|foo|]: "foo", boo: "boo" };
|
||||
|
||||
//// // Skip for union types.
|
||||
//// const props6: { foo: { /** @deprecated */ bar: string } | { bar: string, baz: string } } = { foo: { bar: "bar" } };
|
||||
|
@ -36,22 +36,52 @@ verify.getSuggestionDiagnostics([
|
|||
range: ranges[0],
|
||||
reportsDeprecated: true,
|
||||
},
|
||||
...ranges.slice(1, ranges.length - 2).map(range => ({
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range,
|
||||
range: ranges[1],
|
||||
reportsDeprecated: true as const,
|
||||
})),
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[2],
|
||||
reportsDeprecated: true as const,
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[3],
|
||||
reportsDeprecated: true as const,
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[4],
|
||||
reportsDeprecated: true as const,
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[5],
|
||||
reportsDeprecated: true as const,
|
||||
},
|
||||
{
|
||||
message: "'callback' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[ranges.length - 2],
|
||||
range: ranges[6],
|
||||
reportsDeprecated: true,
|
||||
},
|
||||
{
|
||||
message: "'callback' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[ranges.length - 1],
|
||||
range: ranges[7],
|
||||
reportsDeprecated: true,
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[8],
|
||||
reportsDeprecated: true as const,
|
||||
},
|
||||
])
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
//// func({ [|foo|], bar, [|callback|] });
|
||||
//// func({ bar, [|callback|]() {} });
|
||||
|
||||
//// // Skip if there is a type incompatibility error.
|
||||
//// func({ foo: "foo", boo: "boo" });
|
||||
//// // Do not skip if there is a type incompatibility error.
|
||||
//// func({ [|foo|]: "foo", boo: "boo" });
|
||||
|
||||
//// // Skip for union types.
|
||||
//// function test(_args: { foo: { /** @deprecated */ bar: string } | { bar: string, baz: string } }) {}
|
||||
|
@ -37,22 +37,52 @@ verify.getSuggestionDiagnostics([
|
|||
range: ranges[0],
|
||||
reportsDeprecated: true,
|
||||
},
|
||||
...ranges.slice(1, ranges.length - 2).map(range => ({
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range,
|
||||
range: ranges[1],
|
||||
reportsDeprecated: true as const,
|
||||
})),
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[2],
|
||||
reportsDeprecated: true as const,
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[3],
|
||||
reportsDeprecated: true as const,
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[4],
|
||||
reportsDeprecated: true as const,
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[5],
|
||||
reportsDeprecated: true as const,
|
||||
},
|
||||
{
|
||||
message: "'callback' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[ranges.length - 2],
|
||||
range: ranges[6],
|
||||
reportsDeprecated: true,
|
||||
},
|
||||
{
|
||||
message: "'callback' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[ranges.length - 1],
|
||||
range: ranges[7],
|
||||
reportsDeprecated: true,
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[8],
|
||||
reportsDeprecated: true,
|
||||
},
|
||||
])
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/// <reference path="fourslash.ts" />
|
||||
// @Filename: a.tsx
|
||||
//// type Props = {
|
||||
//// /** @deprecated */
|
||||
|
@ -19,16 +20,16 @@
|
|||
|
||||
//// <Component [|bool|] [|callback|]={() => {}} [|foo|]="foo" bar="bar" baz={{ [|foo|]: true }} />;
|
||||
|
||||
//// // Skip spread in jsx.
|
||||
//// <Component {...{ foo: "foo", bar: "bar" }} />;
|
||||
//// // Do not skip spread in jsx
|
||||
//// <Component {...{ [|foo|]: "foo", bar: "bar" }} />;
|
||||
|
||||
//// // Skip if there is a type incompatibility error.
|
||||
//// <Component foo="" boo="" />;
|
||||
//// <Component {...{ foo: "foo", boo: "boo" }} />;
|
||||
//// // Do not skip if there is a type incompatibility error.
|
||||
//// <Component [|foo|]="" boo="" />;
|
||||
//// <Component {...{ [|foo|]: "foo", boo: "boo" }} />;
|
||||
|
||||
//// // Skip for union types.
|
||||
//// const Component2 = (_props: { foo: { /** @deprecated */ bar: string } | { bar: string, baz: string } }) => <div />;
|
||||
//// <Component foo={{ bar: "bar" }} />;
|
||||
//// <Component2 foo={{ bar: "bar" }} />;
|
||||
|
||||
goTo.file('a.tsx')
|
||||
const ranges = test.ranges();
|
||||
|
@ -46,10 +47,34 @@ verify.getSuggestionDiagnostics([
|
|||
range: ranges[1],
|
||||
reportsDeprecated: true,
|
||||
},
|
||||
...ranges.slice(2).map(range => ({
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range,
|
||||
range: ranges[2],
|
||||
reportsDeprecated: true as const,
|
||||
}))
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[3],
|
||||
reportsDeprecated: true as const,
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[4],
|
||||
reportsDeprecated: true as const,
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[5],
|
||||
reportsDeprecated: true as const,
|
||||
},
|
||||
{
|
||||
message: "'foo' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[6],
|
||||
reportsDeprecated: true as const,
|
||||
},
|
||||
])
|
||||
|
|
|
@ -8,16 +8,9 @@
|
|||
//// return <div />;
|
||||
//// }
|
||||
|
||||
//// overloadFunc({ [|a|]: true }) />;
|
||||
//// overloadFunc({ a: true, b: true }) />;
|
||||
//// overloadFunc({ [|a|]: true });
|
||||
//// overloadFunc({ a: true, b: true });
|
||||
|
||||
const ranges = test.ranges();
|
||||
|
||||
verify.getSuggestionDiagnostics([
|
||||
{
|
||||
message: "'a' is deprecated.",
|
||||
code: 6385,
|
||||
range: ranges[0],
|
||||
reportsDeprecated: true,
|
||||
}
|
||||
])
|
||||
verify.getSuggestionDiagnostics([])
|
||||
|
|
Loading…
Reference in a new issue