13af6ab5fSopenharmony_ci/*
23af6ab5fSopenharmony_ci * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ciimport * as ts from 'typescript';
173af6ab5fSopenharmony_ci
183af6ab5fSopenharmony_cifunction isInstanceofContext(tsIdentStart: ts.Node): boolean {
193af6ab5fSopenharmony_ci  return (
203af6ab5fSopenharmony_ci    ts.isBinaryExpression(tsIdentStart.parent) &&
213af6ab5fSopenharmony_ci    tsIdentStart.parent.operatorToken.kind === ts.SyntaxKind.InstanceOfKeyword
223af6ab5fSopenharmony_ci  );
233af6ab5fSopenharmony_ci}
243af6ab5fSopenharmony_ci
253af6ab5fSopenharmony_cifunction isNewExpressionContext(tsIdentStart: ts.Node): boolean {
263af6ab5fSopenharmony_ci  return ts.isNewExpression(tsIdentStart.parent) && tsIdentStart === tsIdentStart.parent.expression;
273af6ab5fSopenharmony_ci}
283af6ab5fSopenharmony_ci
293af6ab5fSopenharmony_ci/*
303af6ab5fSopenharmony_ci * If identifier is the right-most name of Property Access chain or Qualified name,
313af6ab5fSopenharmony_ci * or it's a separate identifier expression, then identifier is being referenced as an value.
323af6ab5fSopenharmony_ci */
333af6ab5fSopenharmony_cifunction isQualifiedNameContext(tsIdentStart: ts.Node, tsIdentifier: ts.Identifier): boolean {
343af6ab5fSopenharmony_ci  // rightmost in AST is rightmost in qualified name chain
353af6ab5fSopenharmony_ci  return ts.isQualifiedName(tsIdentStart) && tsIdentifier !== tsIdentStart.right;
363af6ab5fSopenharmony_ci}
373af6ab5fSopenharmony_ci
383af6ab5fSopenharmony_cifunction isPropertyAccessContext(tsIdentStart: ts.Node, tsIdentifier: ts.Identifier): boolean {
393af6ab5fSopenharmony_ci  // rightmost in AST is rightmost in qualified name chain
403af6ab5fSopenharmony_ci  return ts.isPropertyAccessExpression(tsIdentStart) && tsIdentifier !== tsIdentStart.name;
413af6ab5fSopenharmony_ci}
423af6ab5fSopenharmony_ci
433af6ab5fSopenharmony_cifunction getQualifiedStart(ident: ts.Node): ts.Node {
443af6ab5fSopenharmony_ci  let qualifiedStart: ts.Node = ident;
453af6ab5fSopenharmony_ci  while (ts.isPropertyAccessExpression(qualifiedStart.parent) || ts.isQualifiedName(qualifiedStart.parent)) {
463af6ab5fSopenharmony_ci    qualifiedStart = qualifiedStart.parent;
473af6ab5fSopenharmony_ci  }
483af6ab5fSopenharmony_ci  return qualifiedStart;
493af6ab5fSopenharmony_ci}
503af6ab5fSopenharmony_ci
513af6ab5fSopenharmony_cifunction isEnumPropAccess(ident: ts.Identifier, tsSym: ts.Symbol, context: ts.Node): boolean {
523af6ab5fSopenharmony_ci  return (
533af6ab5fSopenharmony_ci    ts.isElementAccessExpression(context) &&
543af6ab5fSopenharmony_ci    !!(tsSym.flags & ts.SymbolFlags.Enum) &&
553af6ab5fSopenharmony_ci    (context.expression === ident ||
563af6ab5fSopenharmony_ci      ts.isPropertyAccessExpression(context.expression) && context.expression.name === ident)
573af6ab5fSopenharmony_ci  );
583af6ab5fSopenharmony_ci}
593af6ab5fSopenharmony_ci
603af6ab5fSopenharmony_cifunction isValidParent(parent: ts.Node): boolean {
613af6ab5fSopenharmony_ci  // treat TypeQuery as valid because it's already forbidden (FaultID.TypeQuery)
623af6ab5fSopenharmony_ci  return (
633af6ab5fSopenharmony_ci    ts.isTypeNode(parent) && !ts.isTypeOfExpression(parent) ||
643af6ab5fSopenharmony_ci    ts.isExpressionWithTypeArguments(parent) ||
653af6ab5fSopenharmony_ci    ts.isExportAssignment(parent) ||
663af6ab5fSopenharmony_ci    ts.isExportSpecifier(parent) ||
673af6ab5fSopenharmony_ci    ts.isMetaProperty(parent) ||
683af6ab5fSopenharmony_ci    ts.isImportClause(parent) ||
693af6ab5fSopenharmony_ci    ts.isClassLike(parent) ||
703af6ab5fSopenharmony_ci    ts.isInterfaceDeclaration(parent) ||
713af6ab5fSopenharmony_ci    ts.isModuleDeclaration(parent) ||
723af6ab5fSopenharmony_ci    ts.isEnumDeclaration(parent) ||
733af6ab5fSopenharmony_ci    ts.isNamespaceImport(parent) ||
743af6ab5fSopenharmony_ci    ts.isImportSpecifier(parent) ||
753af6ab5fSopenharmony_ci    ts.isImportEqualsDeclaration(parent)
763af6ab5fSopenharmony_ci  );
773af6ab5fSopenharmony_ci}
783af6ab5fSopenharmony_ci
793af6ab5fSopenharmony_ciexport function identiferUseInValueContext(ident: ts.Identifier, tsSym: ts.Symbol): boolean {
803af6ab5fSopenharmony_ci  const qualifiedStart = getQualifiedStart(ident);
813af6ab5fSopenharmony_ci  const parent = qualifiedStart.parent;
823af6ab5fSopenharmony_ci  const isValidUse =
833af6ab5fSopenharmony_ci    isValidParent(parent) ||
843af6ab5fSopenharmony_ci    isEnumPropAccess(ident, tsSym, parent) ||
853af6ab5fSopenharmony_ci    isQualifiedNameContext(qualifiedStart, ident) ||
863af6ab5fSopenharmony_ci    isPropertyAccessContext(qualifiedStart, ident) ||
873af6ab5fSopenharmony_ci    isNewExpressionContext(qualifiedStart) ||
883af6ab5fSopenharmony_ci    isInstanceofContext(qualifiedStart);
893af6ab5fSopenharmony_ci  return !isValidUse;
903af6ab5fSopenharmony_ci}
91