• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import * as ts from 'typescript';
17
18function isInstanceofContext(tsIdentStart: ts.Node): boolean {
19  return ts.isBinaryExpression(tsIdentStart.parent) &&
20    tsIdentStart.parent.operatorToken.kind === ts.SyntaxKind.InstanceOfKeyword
21}
22
23function isNewExpressionContext(tsIdentStart: ts.Node): boolean {
24  return ts.isNewExpression(tsIdentStart.parent) && tsIdentStart === tsIdentStart.parent.expression
25}
26
27function isQualifiedNameContext(tsIdentStart: ts.Node, tsIdentifier: ts.Identifier): boolean {
28  // rightmost in AST is rightmost in qualified name chain
29  return ts.isQualifiedName(tsIdentStart) && tsIdentifier !== tsIdentStart.right
30}
31
32function isPropertyAccessContext(tsIdentStart: ts.Node, tsIdentifier: ts.Identifier): boolean {
33  // rightmost in AST is rightmost in qualified name chain
34  return ts.isPropertyAccessExpression(tsIdentStart) && tsIdentifier !== tsIdentStart.name
35}
36
37function getQualifiedStart(ident: ts.Node): ts.Node {
38  let qualifiedStart: ts.Node = ident;
39  while (ts.isPropertyAccessExpression(qualifiedStart.parent) || ts.isQualifiedName(qualifiedStart.parent)) {
40    qualifiedStart = qualifiedStart.parent;
41  }
42  return qualifiedStart;
43}
44
45function isEnumPropAccess(ident: ts.Identifier, tsSym: ts.Symbol, context: ts.Node): boolean {
46  return ts.isElementAccessExpression(context) &&
47    (context as ts.ElementAccessExpression).expression == ident &&
48    !!(tsSym.flags & ts.SymbolFlags.Enum);
49}
50
51function isValidTypeNode(node: ts.TypeNode): boolean {
52  return !ts.isTypeOfExpression(node);
53}
54
55export function identiferUseInValueContext(
56  ident: ts.Identifier, tsSym: ts.Symbol
57) {
58  let qualifiedStart = getQualifiedStart(ident);
59  let parent = qualifiedStart.parent;
60
61  return !(
62    // treat TypeQuery as valid because it's already forbidden (FaultID.TypeQuery)
63    ts.isTypeNode(parent) && isValidTypeNode(parent) ||
64    // If identifier is the right-most name of Property Access chain or Qualified name,
65    // or it's a separate identifier expression, then identifier is being referenced as an value.
66    isEnumPropAccess(ident, tsSym, parent) ||
67    ts.isExpressionWithTypeArguments(parent) ||
68    ts.isExportAssignment(parent) ||
69    ts.isExportSpecifier(parent) ||
70    ts.isMetaProperty(parent) ||
71    ts.isImportClause(parent) ||
72    ts.isClassLike(parent) ||
73    ts.isInterfaceDeclaration(parent) ||
74    ts.isModuleDeclaration(parent) ||
75    ts.isEnumDeclaration(parent) ||
76    ts.isNamespaceImport(parent) ||
77    ts.isImportSpecifier(parent) ||
78    isQualifiedNameContext(qualifiedStart, ident) ||
79    isPropertyAccessContext(qualifiedStart, ident) ||
80    isNewExpressionContext(qualifiedStart) ||
81    isInstanceofContext(qualifiedStart) ||
82    ts.isImportEqualsDeclaration(parent)
83  );
84}
85