Relax recursive type alianses in ArkTS

Issue: https://gitee.com/openharmony/third_party_typescript/issues/I81KE0
Test: tsc test

Signed-off-by: xucheng46 <xucheng46@huawei.com>
Change-Id: I368c384293866ca919edff46671f6593a01de4e0
This commit is contained in:
xucheng46 2023-09-15 09:31:23 +08:00
parent 066e8cfb4c
commit 17e6724012
12 changed files with 201 additions and 240 deletions

View File

@ -40,4 +40,5 @@ tmp
app_define.json
VersionSet.xml
build_package/
OAT.xml
OAT.xml
bundle.json

View File

@ -3341,8 +3341,8 @@ namespace ts {
// It should in standard mode, or will return before.
if (isSoFile && moduleNotFoundError !== undefined &&
((currentSourceFile && currentSourceFile.fileName.indexOf("/oh_modules/") !== -1) ||
(resolvedModule && resolvedModule.resolvedFileName.indexOf("/oh_modules/") !== -1))) {
((currentSourceFile && normalizePath(currentSourceFile.fileName).indexOf("/oh_modules/") !== -1) ||
(resolvedModule && normalizePath(resolvedModule.resolvedFileName).indexOf("/oh_modules/") !== -1))) {
const diagnostic = createDiagnosticForNode(errorNode, Diagnostics.Currently_module_for_0_is_not_verified_If_you_re_importing_napi_its_verification_will_be_enabled_in_later_SDK_version_Please_make_sure_the_corresponding_d_ts_file_is_provided_and_the_napis_are_correctly_declared, moduleReference);
diagnostics.add(diagnostic);
moduleNotFoundError = undefined;

View File

@ -1935,7 +1935,7 @@ namespace ts {
const messageFlag = item.messageText !== (options.isCompatibleVersion ?
Diagnostics.Importing_ArkTS_files_in_JS_and_TS_files_is_about_to_be_forbidden.message :
Diagnostics.Importing_ArkTS_files_in_JS_and_TS_files_is_forbidden.message);
const isOhModule = item.file?.fileName.indexOf("/oh_modules/") !== -1;
const isOhModule = (item.file !== undefined) && (normalizePath(item.file.fileName).indexOf("/oh_modules/") !== -1);
const isApplicationsStandard = (item.file !== undefined) && (item.file.fileName.indexOf("/applications/standard/") !== -1);
return !((item.file?.scriptKind === ScriptKind.TS && item.file?.isDeclarationFile && messageFlag) || isOhModule || isApplicationsStandard);
});

View File

@ -144,7 +144,7 @@ cookBookTag[121] = "\"require\" and \"import\" assignment are not supported (ark
cookBookTag[122] = "";
cookBookTag[123] = "";
cookBookTag[124] = "";
cookBookTag[125] = "Re-exporting is supported with restrictions (arkts-limited-reexport)";
cookBookTag[125] = "";
cookBookTag[126] = "\"export = ...\" assignment is not supported (arkts-no-export-assignment)";
cookBookTag[127] = "Special \"export type\" declarations are not supported (arkts-no-special-exports)";
cookBookTag[128] = "Ambient module declaration is not supported (arkts-no-ambient-decls)";

View File

@ -21,7 +21,8 @@ function makeDiag(category: DiagnosticCategory, code: number, file: SourceFile,
export function translateDiag(srcFile: SourceFile, problemInfo: ProblemInfo): Diagnostic {
const LINTER_MSG_CODE_START = -1;
return makeDiag(DiagnosticCategory.Error, LINTER_MSG_CODE_START /*+ problemInfo.ruleTag */, srcFile , problemInfo.start, (problemInfo.end - problemInfo.start + 1), problemInfo.rule);
const severity = (problemInfo.severity === Utils.ProblemSeverity.ERROR ? DiagnosticCategory.Error : DiagnosticCategory.Warning);
return makeDiag(severity, LINTER_MSG_CODE_START /*+ problemInfo.ruleTag */, srcFile , problemInfo.start, (problemInfo.end - problemInfo.start + 1), problemInfo.rule);
}
export function runArkTSLinter(tsProgram: Program, host: CompilerHost, srcFile?: SourceFile): Diagnostic[] {

View File

@ -30,7 +30,7 @@ export enum FaultID {
NonDeclarationInNamespace, GeneratorFunction, FunctionContainsThis, PropertyAccessByIndex, JsxElement,
EnumMemberNonConstInit, ImplementsClass, NoUndefinedPropAccess, MultipleStaticBlocks, ThisType,
IntefaceExtendDifProps, StructuralIdentity, TypeOnlyImport, TypeOnlyExport, DefaultImport,
LimitedReExporting, ExportAssignment, ImportAssignment, PropertyRuntimeCheck,
ExportAssignment, ImportAssignment, PropertyRuntimeCheck,
GenericCallNoTypeArgs, ParameterProperties,
InstanceofUnsupported, ShorthandAmbientModuleDecl, WildcardsInModuleName, UMDModuleDefinition,
NewTarget, DefiniteAssignment, IifeAsNamespace, Prototype, GlobalThis,
@ -85,7 +85,6 @@ faultsAttrs[FaultID.JsxElement] = { cookBookRef: "54", };
faultsAttrs[FaultID.UnaryArithmNotNumber] = { cookBookRef: "55", };
faultsAttrs[FaultID.DeleteOperator] = { cookBookRef: "59", };
faultsAttrs[FaultID.TypeQuery] = { cookBookRef: "60", };
// remove as rule#61: FaultID.BitOpWithWrongType => { cookBookRef: "61", };
faultsAttrs[FaultID.InstanceofUnsupported] = { cookBookRef: "65", };
faultsAttrs[FaultID.InOperator] = { cookBookRef: "66", };
faultsAttrs[FaultID.DestructuringAssignment] = { migratable: true, cookBookRef: "69", };
@ -119,7 +118,6 @@ faultsAttrs[FaultID.ImportFromPath] = { cookBookRef: "119", };
faultsAttrs[FaultID.TypeOnlyImport] = { migratable: true, cookBookRef: "118", };
faultsAttrs[FaultID.DefaultImport] = { migratable: true, cookBookRef: "120", };
faultsAttrs[FaultID.ImportAssignment] = { cookBookRef: "121", };
faultsAttrs[FaultID.LimitedReExporting] = { cookBookRef: "125", };
faultsAttrs[FaultID.ExportAssignment] = { cookBookRef: "126", };
faultsAttrs[FaultID.TypeOnlyExport] = { migratable: true, cookBookRef: "127", };
faultsAttrs[FaultID.ShorthandAmbientModuleDecl] = { cookBookRef: "128", };
@ -142,8 +140,8 @@ faultsAttrs[FaultID.ErrorSuppression] = { cookBookRef: "146", };
faultsAttrs[FaultID.UnsupportedDecorators] = { cookBookRef: "148", };
faultsAttrs[FaultID.ClassAsObject] = { cookBookRef: "149", };
faultsAttrs[FaultID.ImportAfterStatement] = { cookBookRef: "150", };
faultsAttrs[FaultID.EsObjectType] = { cookBookRef: "8" };
faultsAttrs[FaultID.EsObjectAssignment] = { cookBookRef: "8" };
faultsAttrs[FaultID.EsObjectAccess] = { cookBookRef: "8" };
faultsAttrs[FaultID.EsObjectType] = { warning: true, cookBookRef: "8" };
faultsAttrs[FaultID.EsObjectAssignment] = { warning: true, cookBookRef: "8" };
faultsAttrs[FaultID.EsObjectAccess] = { warning: true, cookBookRef: "8" };
}
}

View File

@ -174,11 +174,6 @@ export class TypeScriptLinter {
public incrementCounters(node: Node | CommentRange, faultId: number, autofixable = false, autofix?: Autofix[]): void {
if (!TypeScriptLinter.strictMode && faultsAttrs[faultId].migratable) { return; } // In relax mode skip migratable
// Relax EsObject
if (faultId === FaultID.EsObjectType || faultId === FaultID.EsObjectAssignment || faultId === FaultID.EsObjectAccess) {
return;
}
const startPos = Utils.getStartPos(node);
const endPos = Utils.getEndPos(node);
@ -305,14 +300,13 @@ export class TypeScriptLinter {
}
private countDeclarationsWithDuplicateName(
symbol: Symbol | undefined, tsDeclNode: Node, tsDeclKind?: SyntaxKind
tsNode: Node, tsDeclNode: Node, tsDeclKind?: ts.SyntaxKind
): void {
// Sanity check.
if (!symbol) return;
const symbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsNode);
// If specific declaration kind is provided, check against it.
// Otherwise, use syntax kind of corresponding declaration node.
if (Utils.symbolHasDuplicateName(symbol, tsDeclKind ?? tsDeclNode.kind)) {
if (!!symbol && Utils.symbolHasDuplicateName(symbol, tsDeclKind ?? tsDeclNode.kind)) {
this.incrementCounters(tsDeclNode, FaultID.DeclWithDuplicateName);
}
}
@ -414,9 +408,9 @@ export class TypeScriptLinter {
}
private isIIFEasNamespace(tsExpr: PropertyAccessExpression): boolean {
const nameSymbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsExpr.name);
const nameSymbol = Utils.trueSymbolAtLocation(tsExpr.name);
if (!nameSymbol) {
const leftHandSymbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsExpr.expression);
const leftHandSymbol = Utils.trueSymbolAtLocation(tsExpr.expression);
if (leftHandSymbol) {
const decls = leftHandSymbol.getDeclarations();
if (!decls || decls.length !== 1) return false;
@ -441,12 +435,12 @@ export class TypeScriptLinter {
return false;
}
// Check if property symbol is "Prototype"
const propAccessSym = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsPropertyAccess);
const propAccessSym = Utils.trueSymbolAtLocation(tsPropertyAccess);
if (Utils.isPrototypeSymbol(propAccessSym)) return true;
// Check if symbol of LHS-expression is Class or Function.
const tsBaseExpr = tsPropertyAccess.expression;
const baseExprSym = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsBaseExpr);
const baseExprSym = Utils.trueSymbolAtLocation(tsBaseExpr);
if (Utils.isTypeSymbol(baseExprSym) || Utils.isFunctionSymbol(baseExprSym)) {
return true;
}
@ -580,11 +574,9 @@ export class TypeScriptLinter {
private handleEnumDeclaration(node: Node): void {
const enumNode = node as EnumDeclaration;
this.countDeclarationsWithDuplicateName(
TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(enumNode.name), enumNode
);
this.countDeclarationsWithDuplicateName(enumNode.name, enumNode);
const enumSymbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(enumNode.name);
const enumSymbol = Utils.trueSymbolAtLocation(enumNode.name);
if (!enumSymbol) return;
const enumDecls = enumSymbol.getDeclarations();
@ -604,7 +596,7 @@ export class TypeScriptLinter {
private handleInterfaceDeclaration(node: Node): void {
const interfaceNode = node as InterfaceDeclaration;
const iSymbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(interfaceNode.name);
const iSymbol = Utils.trueSymbolAtLocation(interfaceNode.name);
const iDecls = iSymbol ? iSymbol.getDeclarations() : null;
if (iDecls) {
// Since type checker merges all declarations with the same name
@ -621,9 +613,7 @@ export class TypeScriptLinter {
if (interfaceNode.heritageClauses) this.interfaceInharitanceLint(node, interfaceNode.heritageClauses);
this.countDeclarationsWithDuplicateName(
TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(interfaceNode.name), interfaceNode
);
this.countDeclarationsWithDuplicateName(interfaceNode.name, interfaceNode);
}
private handleThrowStatement(node: Node): void {
@ -706,7 +696,7 @@ export class TypeScriptLinter {
if (this.isPrototypePropertyAccess(propertyAccessNode)) {
this.incrementCounters(propertyAccessNode.name, FaultID.Prototype);
}
const symbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(propertyAccessNode);
const symbol = Utils.trueSymbolAtLocation(propertyAccessNode);
if(!!symbol && Utils.isSymbolAPI(symbol)) {
this.incrementCounters(node, FaultID.SymbolType);
}
@ -876,9 +866,7 @@ export class TypeScriptLinter {
const tsFunctionDeclaration = node as FunctionDeclaration;
if (!tsFunctionDeclaration.type) this.handleMissingReturnType(tsFunctionDeclaration);
if (tsFunctionDeclaration.name) {
this.countDeclarationsWithDuplicateName(
TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsFunctionDeclaration.name), tsFunctionDeclaration
);
this.countDeclarationsWithDuplicateName(tsFunctionDeclaration.name, tsFunctionDeclaration);
}
if (tsFunctionDeclaration.body && this.functionContainsThis(tsFunctionDeclaration.body)) {
this.incrementCounters(node, FaultID.FunctionContainsThis);
@ -994,8 +982,8 @@ export class TypeScriptLinter {
this.incrementCounters(node, FaultID.DestructuringAssignment);
}
if (isPropertyAccessExpression(tsLhsExpr)) {
const tsLhsSymbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsLhsExpr);
const tsLhsBaseSymbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsLhsExpr.expression);
const tsLhsSymbol = Utils.trueSymbolAtLocation(tsLhsExpr);
const tsLhsBaseSymbol = Utils.trueSymbolAtLocation(tsLhsExpr.expression);
if (tsLhsSymbol && (tsLhsSymbol.flags & SymbolFlags.Method)) {
this.incrementCounters(tsLhsExpr, FaultID.NoUndefinedPropAccess);
}
@ -1059,7 +1047,7 @@ export class TypeScriptLinter {
}
else if (tsBinaryExpr.operatorToken.kind === SyntaxKind.InstanceOfKeyword) {
const leftExpr = Utils.unwrapParenthesized(tsBinaryExpr.left);
const leftSymbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(leftExpr);
const leftSymbol = Utils.trueSymbolAtLocation(leftExpr);
// In STS, the left-hand side expression may be of any reference type, otherwise
// a compile-time error occurs. In addition, the left operand in STS cannot be a type.
if (tsLhsExpr.kind === SyntaxKind.ThisKeyword) {
@ -1097,10 +1085,7 @@ export class TypeScriptLinter {
const visitBindingPatternNames = (tsBindingName: BindingName): void => {
if (isIdentifier(tsBindingName)) {
// The syntax kind of the declaration is defined here by the parent of 'BindingName' node.
this.countDeclarationsWithDuplicateName(
TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsBindingName), tsBindingName,
tsBindingName.parent.kind
);
this.countDeclarationsWithDuplicateName(tsBindingName, tsBindingName, tsBindingName.parent.kind);
}
else {
for (const tsBindingElem of tsBindingName.elements) {
@ -1171,24 +1156,16 @@ export class TypeScriptLinter {
this.staticBlocks.clear();
if (tsClassDecl.name) {
this.countDeclarationsWithDuplicateName(
TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsClassDecl.name),
tsClassDecl
);
this.countDeclarationsWithDuplicateName(tsClassDecl.name, tsClassDecl);
}
this.countClassMembersWithDuplicateName(tsClassDecl);
const tsClassDeclType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsClassDecl);
const visitHClause = (hClause: HeritageClause) => {
for (const tsTypeExpr of hClause.types) {
const tsExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsTypeExpr.expression);
if (tsExprType.isClass() && hClause.token === SyntaxKind.ImplementsKeyword) {
this.incrementCounters(tsTypeExpr, FaultID.ImplementsClass);
}
else if (Utils.typeIsRecursive(tsClassDeclType, TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsTypeExpr))) {
this.incrementCounters(tsTypeExpr, FaultID.ClassAsObject);
}
}
};
@ -1206,10 +1183,7 @@ export class TypeScriptLinter {
private handleModuleDeclaration(node: Node): void {
const tsModuleDecl = node as ModuleDeclaration;
this.countDeclarationsWithDuplicateName(
TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsModuleDecl.name),
tsModuleDecl
);
this.countDeclarationsWithDuplicateName(tsModuleDecl.name, tsModuleDecl);
const tsModuleBody = tsModuleDecl.body;
const tsModifiers = tsModuleDecl.modifiers; // TSC 4.2 doesn't have 'getModifiers()' method
@ -1248,20 +1222,13 @@ export class TypeScriptLinter {
private handleTypeAliasDeclaration(node: Node): void {
const tsTypeAlias = node as TypeAliasDeclaration;
this.countDeclarationsWithDuplicateName(
TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsTypeAlias.name), tsTypeAlias
);
if (Utils.typeIsRecursive(TypeScriptLinter.tsTypeChecker.getTypeAtLocation(node))) {
this.incrementCounters(tsTypeAlias, FaultID.ClassAsObject);
}
this.countDeclarationsWithDuplicateName(tsTypeAlias.name, tsTypeAlias);
}
private handleImportClause(node: Node): void {
const tsImportClause = node as ImportClause;
if (tsImportClause.name) {
this.countDeclarationsWithDuplicateName(
TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsImportClause.name), tsImportClause
);
this.countDeclarationsWithDuplicateName(tsImportClause.name, tsImportClause);
}
if (tsImportClause.namedBindings && isNamedImports(tsImportClause.namedBindings)) {
@ -1289,16 +1256,12 @@ export class TypeScriptLinter {
private handleImportSpecifier(node: Node): void {
const tsImportSpecifier = node as ImportSpecifier;
this.countDeclarationsWithDuplicateName(
TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsImportSpecifier.name), tsImportSpecifier
);
this.countDeclarationsWithDuplicateName(tsImportSpecifier.name, tsImportSpecifier);
}
private handleNamespaceImport(node: Node): void {
const tsNamespaceImport = node as NamespaceImport;
this.countDeclarationsWithDuplicateName(
TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsNamespaceImport.name), tsNamespaceImport
);
this.countDeclarationsWithDuplicateName(tsNamespaceImport.name, tsNamespaceImport);
}
private handleTypeAssertionExpression(node: Node): void {
@ -1341,11 +1304,10 @@ export class TypeScriptLinter {
private handleIdentifier(node: Node): void {
const tsIdentifier = node as Identifier;
const tsIdentSym = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsIdentifier);
const tsIdentSym = Utils.trueSymbolAtLocation(tsIdentifier);
if (tsIdentSym) {
this.handleNamespaceAsObject(tsIdentifier, tsIdentSym);
this.handleClassAsObject(tsIdentifier, tsIdentSym);
this.handleRestrictedValues(tsIdentifier, tsIdentSym);
if (
(tsIdentSym.flags & SymbolFlags.Module) !== 0 &&
@ -1360,85 +1322,62 @@ export class TypeScriptLinter {
}
}
private handleNamespaceAsObject(tsIdentifier: Identifier, tsIdentSym: Symbol): void {
if (
tsIdentSym &&
(tsIdentSym.getFlags() & SymbolFlags.Module) !== 0 &&
(tsIdentSym.getFlags() & SymbolFlags.Variable) === 0 &&
!isModuleDeclaration(tsIdentifier.parent)
) {
// If module name is duplicated by another declaration, this increases the possibility
// of finding a lot of false positives. Thus, do not check further in that case.
if (!Utils.symbolHasDuplicateName(tsIdentSym, SyntaxKind.ModuleDeclaration)) {
// If module name is the right-most name of Property Access chain or Qualified name,
// or it's a separate identifier expression, then module is being referenced as an object.
let tsIdentParent: Node = tsIdentifier;
private handleRestrictedValues(tsIdentifier: Identifier, tsIdentSym: Symbol) {
const illegalValues = SymbolFlags.Class | SymbolFlags.ConstEnum | SymbolFlags.RegularEnum | SymbolFlags.ValueModule;
while (isPropertyAccessExpression(tsIdentParent.parent) || isQualifiedName(tsIdentParent.parent)) {
tsIdentParent = tsIdentParent.parent;
}
const isNamespace: boolean = (tsIdentSym.getFlags() & SymbolFlags.Namespace) !== 0;
let isEmptyModuleBlock = false;
if (tsIdentSym.declarations && tsIdentSym.declarations.length > 0 && isModuleDeclaration(tsIdentSym.declarations[0])) {
const moduleDecl = tsIdentSym.declarations[0] as ModuleDeclaration;
if (moduleDecl.body && isModuleBlock(moduleDecl.body)) {
const moduleBlock = moduleDecl.body;
if (moduleBlock.statements && moduleBlock.statements.length === 0) {
isEmptyModuleBlock = true;
}
}
}
if (
(!isPropertyAccessExpression(tsIdentParent) && !isQualifiedName(tsIdentParent) && !(isNamespace && isEmptyModuleBlock)) ||
(isPropertyAccessExpression(tsIdentParent) && tsIdentifier === tsIdentParent.name) ||
(isQualifiedName(tsIdentParent) && tsIdentifier === tsIdentParent.right)
) {
this.incrementCounters(tsIdentifier, FaultID.NamespaceAsObject);
}
// If module name is duplicated by another declaration, this increases the possibility
// of finding a lot of false positives. Thus, do not check further in that case.
if ((tsIdentSym.flags & SymbolFlags.ValueModule) != 0) {
if (!!tsIdentSym && Utils.symbolHasDuplicateName(tsIdentSym, SyntaxKind.ModuleDeclaration)) {
return;
}
}
}
private handleClassAsObject(tsIdentifier: Identifier, tsIdentSym: Symbol) {
// Only process class references.
if ((tsIdentSym.getFlags() & SymbolFlags.Class) === 0) {
return;
}
// No check for ArkUI struct.
if (Utils.isStruct(tsIdentSym)) {
return;
}
// If class name is the right-most name of Property Access chain or Qualified name,
// or it's a separate identifier expression, then class is being referenced as an object.
let tsIdentStart: Node = tsIdentifier;
if ((tsIdentSym.flags & illegalValues) == 0 || !this.identiferUseInValueContext(tsIdentifier)) {
return;
}
if (tsIdentSym.flags & SymbolFlags.ValueModule) {
this.incrementCounters(tsIdentifier, FaultID.NamespaceAsObject);
}
else {
// missing EnumAsObject
this.incrementCounters(tsIdentifier, FaultID.ClassAsObject);
}
}
private identiferUseInValueContext(
tsIdentifier: Identifier
) {
// If identifier is the right-most name of Property Access chain or Qualified name,
// or it's a separate identifier expression, then identifier is being referenced as an value.
let tsIdentStart: Node = tsIdentifier;
while (isPropertyAccessExpression(tsIdentStart.parent) || isQualifiedName(tsIdentStart.parent)) {
tsIdentStart = tsIdentStart.parent;
}
// contexts where type is used as value, but it's intended
if (isTypeNode(tsIdentStart.parent) ||
isExpressionWithTypeArguments(tsIdentStart.parent) ||
isExportAssignment(tsIdentStart.parent) ||
isExportSpecifier(tsIdentStart.parent) ||
isMetaProperty(tsIdentStart.parent) ||
isImportClause(tsIdentStart.parent) ||
isClassLike(tsIdentStart.parent) ||
isInterfaceDeclaration(tsIdentStart.parent) ||
isModuleDeclaration(tsIdentStart.parent) ||
isNamespaceImport(tsIdentStart.parent) ||
isImportSpecifier(tsIdentStart.parent) ||
(isQualifiedName(tsIdentStart) && tsIdentifier !== tsIdentStart.right) ||
(isPropertyAccessExpression(tsIdentStart) && tsIdentifier !== tsIdentStart.name) ||
(isNewExpression(tsIdentStart.parent) && tsIdentStart === tsIdentStart.parent.expression) ||
(isBinaryExpression(tsIdentStart.parent) && tsIdentStart.parent.operatorToken.kind === SyntaxKind.InstanceOfKeyword)) {
return;
}
this.incrementCounters(tsIdentifier, FaultID.ClassAsObject);
return !(
// treat TypeQuery as valid because it's already forbidden (FaultID.TypeQuery)
(isTypeNode(tsIdentStart.parent) && !isTypeOfExpression(tsIdentStart.parent)) ||
isExpressionWithTypeArguments(tsIdentStart.parent) ||
isExportAssignment(tsIdentStart.parent) ||
isExportSpecifier(tsIdentStart.parent) ||
isMetaProperty(tsIdentStart.parent) ||
isImportClause(tsIdentStart.parent) ||
isClassLike(tsIdentStart.parent) ||
isInterfaceDeclaration(tsIdentStart.parent) ||
isModuleDeclaration(tsIdentStart.parent) ||
isEnumDeclaration(tsIdentStart.parent) ||
isNamespaceImport(tsIdentStart.parent) ||
isImportSpecifier(tsIdentStart.parent) ||
// rightmost in AST is rightmost in qualified name chain
(isQualifiedName(tsIdentStart) && tsIdentifier !== tsIdentStart.right) ||
(isPropertyAccessExpression(tsIdentStart) && tsIdentifier !== tsIdentStart.name) ||
(isNewExpression(tsIdentStart.parent) && tsIdentStart === tsIdentStart.parent.expression) ||
(isBinaryExpression(tsIdentStart.parent) && tsIdentStart.parent.operatorToken.kind === SyntaxKind.InstanceOfKeyword)
);
}
private handleElementAccessExpression(node: Node): void {
@ -1504,11 +1443,6 @@ export class TypeScriptLinter {
// autofix = [ Autofixer.dropTypeOnlyFlag(tsExportDecl) ];
this.incrementCounters(node, FaultID.TypeOnlyExport, true, autofix);
}
const exportClause = tsExportDecl.exportClause;
if(exportClause && isNamespaceExport(exportClause)) {
this.incrementCounters(node, FaultID.LimitedReExporting);
}
}
private handleExportAssignment(node: Node): void {
@ -1574,8 +1508,12 @@ export class TypeScriptLinter {
if (!callSignature) return;
const tsSyntaxKind = isNewExpression(callLikeExpr) ? SyntaxKind.Constructor : SyntaxKind.FunctionDeclaration;
const signDecl = TypeScriptLinter.tsTypeChecker.signatureToSignatureDeclaration(callSignature, tsSyntaxKind,
undefined, NodeBuilderFlags.WriteTypeArgumentsOfSignature | NodeBuilderFlags.IgnoreErrors);
const sym = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(callLikeExpr.expression).symbol;
const signDecl = TypeScriptLinter.tsTypeChecker.signatureToSignatureDeclaration(
callSignature,
tsSyntaxKind,
(!!sym && !!sym.declarations) ? sym.declarations[0] : undefined,
NodeBuilderFlags.WriteTypeArgumentsOfSignature | NodeBuilderFlags.IgnoreErrors);
if (signDecl?.typeArguments) {
const resolvedTypeArgs = signDecl.typeArguments;
@ -1602,7 +1540,7 @@ export class TypeScriptLinter {
`${callableFunction}.bind`,
];
const exprSymbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsCallExpr.expression);
const exprSymbol = Utils.trueSymbolAtLocation(tsCallExpr.expression);
if (exprSymbol === undefined) {
return;
}
@ -1645,7 +1583,7 @@ export class TypeScriptLinter {
const callSignature = TypeScriptLinter.tsTypeChecker.getResolvedSignature(callExpr);
if (!callSignature) return;
const sym = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(callExpr.expression);
const sym = Utils.trueSymbolAtLocation(callExpr.expression);
if (sym) {
const name = sym.getName();
if (
@ -1819,7 +1757,7 @@ export class TypeScriptLinter {
private handleExpressionWithTypeArguments(node: Node) {
const tsTypeExpr = node as ExpressionWithTypeArguments;
const symbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsTypeExpr.expression);
const symbol = Utils.trueSymbolAtLocation(tsTypeExpr.expression);
if (!!symbol && Utils.isEsObjectSymbol(symbol)) {
this.incrementCounters(tsTypeExpr, FaultID.EsObjectType);
}
@ -1888,6 +1826,8 @@ export class TypeScriptLinter {
}
}
private validatedTypesSet = new Set<Type>();
private validateDeclInferredType(
type: Type,
decl: VariableDeclaration | PropertyDeclaration | ParameterDeclaration
@ -1895,12 +1835,6 @@ export class TypeScriptLinter {
if (type.aliasSymbol !== undefined) {
return;
}
if (type.isUnion()) {
for (const unionElem of type.types) {
this.validateDeclInferredType(unionElem, decl);
}
}
if (type.flags & TypeFlags.Object && (type as ObjectType).objectFlags & ObjectFlags.Reference) {
const typeArgs = TypeScriptLinter.tsTypeChecker.getTypeArguments(type as TypeReference);
if (typeArgs) {
@ -1908,6 +1842,16 @@ export class TypeScriptLinter {
this.validateDeclInferredType(typeArg, decl);
}
}
return;
}
if (this.validatedTypesSet.has(type)) {
return;
}
if (type.isUnion()) {
this.validatedTypesSet.add(type);
for (let unionElem of type.types) {
this.validateDeclInferredType(unionElem, decl);
}
}
if (Utils.isAnyType(type)) {

View File

@ -100,7 +100,6 @@ export class LinterConfig {
LinterConfig.nodeDesc[FaultID.TypeOnlyImport] = "Type-only imports";
LinterConfig.nodeDesc[FaultID.TypeOnlyExport] = "Type-only exports";
LinterConfig.nodeDesc[FaultID.DefaultImport] = "Default import declarations";
LinterConfig.nodeDesc[FaultID.LimitedReExporting] = "Limited re-exporting declarations";
LinterConfig.nodeDesc[FaultID.ExportAssignment] = "Export assignments (export = ..)";
LinterConfig.nodeDesc[FaultID.ImportAssignment] = "Import assignments (import = ..)";
LinterConfig.nodeDesc[FaultID.PropertyRuntimeCheck] = "Property-based runtime checks";

View File

@ -209,6 +209,18 @@ export function unwrapParenthesized(tsExpr: Expression): Expression {
return unwrappedExpr;
}
export function followIfAliased(sym: Symbol): Symbol {
if ((sym.getFlags() & SymbolFlags.Alias) !== 0) {
return typeChecker.getAliasedSymbol(sym);
}
return sym;
}
export function trueSymbolAtLocation(node: Node): Symbol | undefined {
const sym = typeChecker.getSymbolAtLocation(node);
return sym === undefined ? undefined : followIfAliased(sym);
}
export function symbolHasDuplicateName(symbol: Symbol, tsDeclKind: SyntaxKind): boolean {
// Type Checker merges all declarations with the same name in one scope into one symbol.
// Thus, check whether the symbol of certain declaration has any declaration with
@ -955,13 +967,13 @@ export const LIMITED_STD_GLOBAL_VAR = ["Infinity", "NaN"];
export const LIMITED_STD_OBJECT_API = [
"__proto__", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__", "assign", "create",
"defineProperties", "defineProperty", "entries", "freeze", "fromEntries", "getOwnPropertyDescriptor",
"getOwnPropertyDescriptors", "getOwnPropertyNames", "getOwnPropertySymbols", "getPrototypeOf", "hasOwn",
"hasOwnProperty", "is", "isExtensible", "isFrozen", "isPrototypeOf", "isSealed", "keys", "preventExtensions",
"propertyIsEnumerable", "seal", "setPrototypeOf", "values"
"getOwnPropertyDescriptors", "getOwnPropertySymbols", "getPrototypeOf", "hasOwnProperty", "is",
"isExtensible", "isFrozen", "isPrototypeOf", "isSealed", "preventExtensions", "propertyIsEnumerable",
"seal", "setPrototypeOf"
];
export const LIMITED_STD_REFLECT_API = [
"apply", "construct", "defineProperty", "deleteProperty", "get", "getOwnPropertyDescriptor", "getPrototypeOf",
"has", "isExtensible", "ownKeys", "preventExtensions", "set", "setPrototypeOf"
"apply", "construct", "defineProperty", "deleteProperty", "getOwnPropertyDescriptor", "getPrototypeOf",
"isExtensible", "preventExtensions", "setPrototypeOf"
];
export const LIMITED_STD_PROXYHANDLER_API = [
"apply", "construct", "defineProperty", "deleteProperty", "get", "getOwnPropertyDescriptor", "getPrototypeOf",
@ -1203,22 +1215,19 @@ export function isDynamicType(type: Type | undefined): boolean | undefined {
// return 'false' if it is not an object of standard library type one.
// In the case of standard library type we need to determine context.
// Check the non-nullable version of type to eliminate 'undefined' type
// Check the non-nullable version of type to eliminate 'undefined' type
// from the union type elements.
type = type.getNonNullableType();
if (type.isUnion()) {
for (const compType of type.types) {
if (isLibraryType(compType)) {
return true;
}
if (!isStdLibraryType(compType) && !isIntrinsicObjectType(compType) && !isAnyType(compType)) {
return false;
const isDynamic = isDynamicType(compType);
if (isDynamic || isDynamic === undefined) {
return isDynamic;
}
}
return undefined;
return false;
}
if (isLibraryType(type)) {
@ -1259,13 +1268,18 @@ export function isDynamicLiteralInitializer(expr: Expression): boolean {
// foo({ ... })
if (isCallExpression(curNode)) {
const callExpr = curNode;
let sym: Symbol | undefined = typeChecker.getTypeAtLocation(callExpr.expression).symbol;
const type = typeChecker.getTypeAtLocation(callExpr.expression);
// this check is a hack to fix #13474, only for tac 4.2
if (isAnyType(type)) return true;
let sym: Symbol | undefined = type.symbol;
if(isLibrarySymbol(sym)) {
return true;
}
// #13483:
// x.foo({ ... }), where 'x' is exported from some library:
// x.foo({ ... }), where 'x' is a variable exported from some library:
if (isPropertyAccessExpression(callExpr.expression)) {
sym = typeChecker.getSymbolAtLocation(callExpr.expression.expression);
if (sym && sym.getFlags() & SymbolFlags.Alias) {

View File

@ -11388,37 +11388,36 @@ declare namespace ts {
TypeOnlyImport = 63,
TypeOnlyExport = 64,
DefaultImport = 65,
LimitedReExporting = 66,
ExportAssignment = 67,
ImportAssignment = 68,
PropertyRuntimeCheck = 69,
GenericCallNoTypeArgs = 70,
ParameterProperties = 71,
InstanceofUnsupported = 72,
ShorthandAmbientModuleDecl = 73,
WildcardsInModuleName = 74,
UMDModuleDefinition = 75,
NewTarget = 76,
DefiniteAssignment = 77,
IifeAsNamespace = 78,
Prototype = 79,
GlobalThis = 80,
UtilityType = 81,
PropertyDeclOnFunction = 82,
FunctionApplyBindCall = 83,
ReadonlyArr = 84,
ConstAssertion = 85,
ImportAssertion = 86,
SpreadOperator = 87,
LimitedStdLibApi = 88,
ErrorSuppression = 89,
StrictDiagnostic = 90,
UnsupportedDecorators = 91,
ImportAfterStatement = 92,
EsObjectType = 93,
EsObjectAssignment = 94,
EsObjectAccess = 95,
LAST_ID = 96
ExportAssignment = 66,
ImportAssignment = 67,
PropertyRuntimeCheck = 68,
GenericCallNoTypeArgs = 69,
ParameterProperties = 70,
InstanceofUnsupported = 71,
ShorthandAmbientModuleDecl = 72,
WildcardsInModuleName = 73,
UMDModuleDefinition = 74,
NewTarget = 75,
DefiniteAssignment = 76,
IifeAsNamespace = 77,
Prototype = 78,
GlobalThis = 79,
UtilityType = 80,
PropertyDeclOnFunction = 81,
FunctionApplyBindCall = 82,
ReadonlyArr = 83,
ConstAssertion = 84,
ImportAssertion = 85,
SpreadOperator = 86,
LimitedStdLibApi = 87,
ErrorSuppression = 88,
StrictDiagnostic = 89,
UnsupportedDecorators = 90,
ImportAfterStatement = 91,
EsObjectType = 92,
EsObjectAssignment = 93,
EsObjectAccess = 94,
LAST_ID = 95
}
class FaultAttributs {
migratable?: boolean;
@ -11460,6 +11459,8 @@ declare namespace ts {
function isNumberLikeType(tsType: Type): boolean;
function hasModifier(tsModifiers: readonly Modifier[] | undefined, tsModifierKind: number): boolean;
function unwrapParenthesized(tsExpr: Expression): Expression;
function followIfAliased(sym: Symbol): Symbol;
function trueSymbolAtLocation(node: Node): Symbol | undefined;
function symbolHasDuplicateName(symbol: Symbol, tsDeclKind: SyntaxKind): boolean;
function isReferenceType(tsType: Type): boolean;
function isPrimitiveType(type: Type): boolean;
@ -11664,8 +11665,8 @@ declare namespace ts {
private handleTypeAssertionExpression;
private handleMethodDeclaration;
private handleIdentifier;
private handleNamespaceAsObject;
private handleClassAsObject;
private handleRestrictedValues;
private identiferUseInValueContext;
private handleElementAccessExpression;
private handleEnumMember;
private handleExportDeclaration;
@ -11693,6 +11694,7 @@ declare namespace ts {
private handleSetAccessor;
private handleDeclarationInferredType;
private handleDefiniteAssignmentAssertion;
private validatedTypesSet;
private validateDeclInferredType;
lint(): void;
}

View File

@ -7605,37 +7605,36 @@ declare namespace ts {
TypeOnlyImport = 63,
TypeOnlyExport = 64,
DefaultImport = 65,
LimitedReExporting = 66,
ExportAssignment = 67,
ImportAssignment = 68,
PropertyRuntimeCheck = 69,
GenericCallNoTypeArgs = 70,
ParameterProperties = 71,
InstanceofUnsupported = 72,
ShorthandAmbientModuleDecl = 73,
WildcardsInModuleName = 74,
UMDModuleDefinition = 75,
NewTarget = 76,
DefiniteAssignment = 77,
IifeAsNamespace = 78,
Prototype = 79,
GlobalThis = 80,
UtilityType = 81,
PropertyDeclOnFunction = 82,
FunctionApplyBindCall = 83,
ReadonlyArr = 84,
ConstAssertion = 85,
ImportAssertion = 86,
SpreadOperator = 87,
LimitedStdLibApi = 88,
ErrorSuppression = 89,
StrictDiagnostic = 90,
UnsupportedDecorators = 91,
ImportAfterStatement = 92,
EsObjectType = 93,
EsObjectAssignment = 94,
EsObjectAccess = 95,
LAST_ID = 96
ExportAssignment = 66,
ImportAssignment = 67,
PropertyRuntimeCheck = 68,
GenericCallNoTypeArgs = 69,
ParameterProperties = 70,
InstanceofUnsupported = 71,
ShorthandAmbientModuleDecl = 72,
WildcardsInModuleName = 73,
UMDModuleDefinition = 74,
NewTarget = 75,
DefiniteAssignment = 76,
IifeAsNamespace = 77,
Prototype = 78,
GlobalThis = 79,
UtilityType = 80,
PropertyDeclOnFunction = 81,
FunctionApplyBindCall = 82,
ReadonlyArr = 83,
ConstAssertion = 84,
ImportAssertion = 85,
SpreadOperator = 86,
LimitedStdLibApi = 87,
ErrorSuppression = 88,
StrictDiagnostic = 89,
UnsupportedDecorators = 90,
ImportAfterStatement = 91,
EsObjectType = 92,
EsObjectAssignment = 93,
EsObjectAccess = 94,
LAST_ID = 95
}
class FaultAttributs {
migratable?: boolean;
@ -7677,6 +7676,8 @@ declare namespace ts {
function isNumberLikeType(tsType: Type): boolean;
function hasModifier(tsModifiers: readonly Modifier[] | undefined, tsModifierKind: number): boolean;
function unwrapParenthesized(tsExpr: Expression): Expression;
function followIfAliased(sym: Symbol): Symbol;
function trueSymbolAtLocation(node: Node): Symbol | undefined;
function symbolHasDuplicateName(symbol: Symbol, tsDeclKind: SyntaxKind): boolean;
function isReferenceType(tsType: Type): boolean;
function isPrimitiveType(type: Type): boolean;
@ -7881,8 +7882,8 @@ declare namespace ts {
private handleTypeAssertionExpression;
private handleMethodDeclaration;
private handleIdentifier;
private handleNamespaceAsObject;
private handleClassAsObject;
private handleRestrictedValues;
private identiferUseInValueContext;
private handleElementAccessExpression;
private handleEnumMember;
private handleExportDeclaration;
@ -7910,6 +7911,7 @@ declare namespace ts {
private handleSetAccessor;
private handleDeclarationInferredType;
private handleDefiniteAssignmentAssertion;
private validatedTypesSet;
private validateDeclInferredType;
lint(): void;
}