Skip to content

Commit 79da510

Browse files
authored
Fix incorrect flags in modifierFlagsCache (#56198)
1 parent 55395f9 commit 79da510

File tree

5 files changed

+122
-56
lines changed

5 files changed

+122
-56
lines changed

src/compiler/types.ts

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -851,25 +851,45 @@ export const enum NodeFlags {
851851
// dprint-ignore
852852
export const enum ModifierFlags {
853853
None = 0,
854-
Export = 1 << 0, // Declarations
855-
Ambient = 1 << 1, // Declarations
856-
Public = 1 << 2, // Property/Method
857-
Private = 1 << 3, // Property/Method
858-
Protected = 1 << 4, // Property/Method
859-
Static = 1 << 5, // Property/Method
860-
Readonly = 1 << 6, // Property/Method
861-
Accessor = 1 << 7, // Property
862-
Abstract = 1 << 8, // Class/Method/ConstructSignature
863-
Async = 1 << 9, // Property/Method/Function
864-
Default = 1 << 10, // Function/Class (export default declaration)
865-
Const = 1 << 11, // Const enum
866-
HasComputedJSDocModifiers = 1 << 12, // Indicates the computed modifier flags include modifiers from JSDoc.
867-
868-
Deprecated = 1 << 13, // Deprecated tag.
869-
Override = 1 << 14, // Override method.
870-
In = 1 << 15, // Contravariance modifier
871-
Out = 1 << 16, // Covariance modifier
872-
Decorator = 1 << 17, // Contains a decorator.
854+
855+
// Syntactic/JSDoc modifiers
856+
Public = 1 << 0, // Property/Method
857+
Private = 1 << 1, // Property/Method
858+
Protected = 1 << 2, // Property/Method
859+
Readonly = 1 << 3, // Property/Method
860+
Override = 1 << 4, // Override method.
861+
862+
// Syntactic-only modifiers
863+
Export = 1 << 5, // Declarations
864+
Abstract = 1 << 6, // Class/Method/ConstructSignature
865+
Ambient = 1 << 7, // Declarations
866+
Static = 1 << 8, // Property/Method
867+
Accessor = 1 << 9, // Property
868+
Async = 1 << 10, // Property/Method/Function
869+
Default = 1 << 11, // Function/Class (export default declaration)
870+
Const = 1 << 12, // Const enum
871+
In = 1 << 13, // Contravariance modifier
872+
Out = 1 << 14, // Covariance modifier
873+
Decorator = 1 << 15, // Contains a decorator.
874+
875+
// JSDoc-only modifiers
876+
Deprecated = 1 << 16, // Deprecated tag.
877+
878+
// Cache-only JSDoc-modifiers. Should match order of Syntactic/JSDoc modifiers, above.
879+
/** @internal */ JSDocPublic = 1 << 23, // if this value changes, `selectEffectiveModifierFlags` must change accordingly
880+
/** @internal */ JSDocPrivate = 1 << 24,
881+
/** @internal */ JSDocProtected = 1 << 25,
882+
/** @internal */ JSDocReadonly = 1 << 26,
883+
/** @internal */ JSDocOverride = 1 << 27,
884+
885+
/** @internal */ SyntacticOrJSDocModifiers = Public | Private | Protected | Readonly | Override,
886+
/** @internal */ SyntacticOnlyModifiers = Export | Ambient | Abstract | Static | Accessor | Async | Default | Const | In | Out | Decorator,
887+
/** @internal */ SyntacticModifiers = SyntacticOrJSDocModifiers | SyntacticOnlyModifiers,
888+
/** @internal */ JSDocCacheOnlyModifiers = JSDocPublic | JSDocPrivate | JSDocProtected | JSDocReadonly | JSDocOverride,
889+
/** @internal */ JSDocOnlyModifiers = Deprecated,
890+
/** @internal */ NonCacheOnlyModifiers = SyntacticOrJSDocModifiers | SyntacticOnlyModifiers | JSDocOnlyModifiers,
891+
892+
HasComputedJSDocModifiers = 1 << 28, // Indicates the computed modifier flags include modifiers from JSDoc.
873893
HasComputedFlags = 1 << 29, // Modifier flags have been computed
874894

875895
AccessibilityModifier = Public | Private | Protected,

src/compiler/utilities.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6928,11 +6928,14 @@ function getModifierFlagsWorker(node: Node, includeJSDoc: boolean, alwaysInclude
69286928
node.modifierFlagsCache = getSyntacticModifierFlagsNoCache(node) | ModifierFlags.HasComputedFlags;
69296929
}
69306930

6931-
if (includeJSDoc && !(node.modifierFlagsCache & ModifierFlags.HasComputedJSDocModifiers) && (alwaysIncludeJSDoc || isInJSFile(node)) && node.parent) {
6932-
node.modifierFlagsCache |= getJSDocModifierFlagsNoCache(node) | ModifierFlags.HasComputedJSDocModifiers;
6931+
if (alwaysIncludeJSDoc || includeJSDoc && isInJSFile(node)) {
6932+
if (!(node.modifierFlagsCache & ModifierFlags.HasComputedJSDocModifiers) && node.parent) {
6933+
node.modifierFlagsCache |= getRawJSDocModifierFlagsNoCache(node) | ModifierFlags.HasComputedJSDocModifiers;
6934+
}
6935+
return selectEffectiveModifierFlags(node.modifierFlagsCache);
69336936
}
69346937

6935-
return node.modifierFlagsCache & ~(ModifierFlags.HasComputedFlags | ModifierFlags.HasComputedJSDocModifiers);
6938+
return selectSyntacticModifierFlags(node.modifierFlagsCache);
69366939
}
69376940

69386941
/**
@@ -6962,22 +6965,35 @@ export function getSyntacticModifierFlags(node: Node): ModifierFlags {
69626965
return getModifierFlagsWorker(node, /*includeJSDoc*/ false);
69636966
}
69646967

6965-
function getJSDocModifierFlagsNoCache(node: Node): ModifierFlags {
6968+
function getRawJSDocModifierFlagsNoCache(node: Node): ModifierFlags {
69666969
let flags = ModifierFlags.None;
69676970
if (!!node.parent && !isParameter(node)) {
69686971
if (isInJSFile(node)) {
6969-
if (getJSDocPublicTagNoCache(node)) flags |= ModifierFlags.Public;
6970-
if (getJSDocPrivateTagNoCache(node)) flags |= ModifierFlags.Private;
6971-
if (getJSDocProtectedTagNoCache(node)) flags |= ModifierFlags.Protected;
6972-
if (getJSDocReadonlyTagNoCache(node)) flags |= ModifierFlags.Readonly;
6973-
if (getJSDocOverrideTagNoCache(node)) flags |= ModifierFlags.Override;
6972+
if (getJSDocPublicTagNoCache(node)) flags |= ModifierFlags.JSDocPublic;
6973+
if (getJSDocPrivateTagNoCache(node)) flags |= ModifierFlags.JSDocPrivate;
6974+
if (getJSDocProtectedTagNoCache(node)) flags |= ModifierFlags.JSDocProtected;
6975+
if (getJSDocReadonlyTagNoCache(node)) flags |= ModifierFlags.JSDocReadonly;
6976+
if (getJSDocOverrideTagNoCache(node)) flags |= ModifierFlags.JSDocOverride;
69746977
}
69756978
if (getJSDocDeprecatedTagNoCache(node)) flags |= ModifierFlags.Deprecated;
69766979
}
69776980

69786981
return flags;
69796982
}
69806983

6984+
function selectSyntacticModifierFlags(flags: ModifierFlags) {
6985+
return flags & ModifierFlags.SyntacticModifiers;
6986+
}
6987+
6988+
function selectEffectiveModifierFlags(flags: ModifierFlags) {
6989+
return (flags & ModifierFlags.NonCacheOnlyModifiers) |
6990+
((flags & ModifierFlags.JSDocCacheOnlyModifiers) >>> 23); // shift ModifierFlags.JSDoc* to match ModifierFlags.*
6991+
}
6992+
6993+
function getJSDocModifierFlagsNoCache(node: Node): ModifierFlags {
6994+
return selectEffectiveModifierFlags(getRawJSDocModifierFlagsNoCache(node));
6995+
}
6996+
69816997
/**
69826998
* Gets the effective ModifierFlags for the provided node, including JSDoc modifiers. The modifier flags cache on the node is ignored.
69836999
*

src/services/codefixes/fixSpelling.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
getModeForUsageLocation,
1111
getTextOfNode,
1212
getTokenAtPosition,
13-
hasSyntacticModifier,
13+
hasOverrideModifier,
1414
ImportDeclaration,
1515
isBinaryExpression,
1616
isClassElement,
@@ -27,7 +27,6 @@ import {
2727
isPropertyAccessExpression,
2828
isQualifiedName,
2929
isStringLiteralLike,
30-
ModifierFlags,
3130
Node,
3231
NodeFlags,
3332
ScriptTarget,
@@ -131,7 +130,7 @@ function getInfo(sourceFile: SourceFile, pos: number, context: CodeFixContextBas
131130
const props = checker.getContextualTypeForArgumentAtIndex(tag, 0);
132131
suggestedSymbol = checker.getSuggestedSymbolForNonexistentJSXAttribute(node, props!);
133132
}
134-
else if (hasSyntacticModifier(parent, ModifierFlags.Override) && isClassElement(parent) && parent.name === node) {
133+
else if (hasOverrideModifier(parent) && isClassElement(parent) && parent.name === node) {
135134
const baseDeclaration = findAncestor(node, isClassLike);
136135
const baseTypeNode = baseDeclaration ? getEffectiveBaseTypeNode(baseDeclaration) : undefined;
137136
const baseType = baseTypeNode ? checker.getTypeAtLocation(baseTypeNode) : undefined;

src/testRunner/unittests/publicApi.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,34 @@ describe("unittests:: Public APIs:: getChild* methods on EndOfFileToken with JSD
231231
assert.notEqual(endOfFileToken.getChildAt(0), /*expected*/ undefined);
232232
});
233233
});
234+
235+
describe("unittests:: Public APIs:: get syntactic and effective modifiers", () => {
236+
it("caches and reports correct flags in TS file", () => {
237+
// https://github.com/microsoft/TypeScript/issues/42189
238+
const content = `
239+
class C {
240+
/** @private */
241+
prop = 1;
242+
}`;
243+
const sourceFile = ts.createSourceFile("/file.ts", content, ts.ScriptTarget.ESNext, /*setParentNodes*/ true);
244+
const classNode = sourceFile.statements[0] as ts.ClassDeclaration;
245+
const propNode = classNode.members[0] as ts.PropertyDeclaration;
246+
assert.equal(ts.ModifierFlags.None, ts.getSyntacticModifierFlags(propNode));
247+
assert.equal(ts.ModifierFlags.None, ts.getEffectiveModifierFlags(propNode));
248+
assert.equal(ts.ModifierFlags.None, ts.getSyntacticModifierFlags(propNode));
249+
});
250+
it("caches and reports correct flags in JS file", () => {
251+
// https://github.com/microsoft/TypeScript/issues/42189
252+
const content = `
253+
class C {
254+
/** @private */
255+
prop = 1;
256+
}`;
257+
const sourceFile = ts.createSourceFile("/file.js", content, ts.ScriptTarget.ESNext, /*setParentNodes*/ true);
258+
const classNode = sourceFile.statements[0] as ts.ClassDeclaration;
259+
const propNode = classNode.members[0] as ts.PropertyDeclaration;
260+
assert.equal(ts.ModifierFlags.None, ts.getSyntacticModifierFlags(propNode));
261+
assert.equal(ts.ModifierFlags.Private, ts.getEffectiveModifierFlags(propNode));
262+
assert.equal(ts.ModifierFlags.None, ts.getSyntacticModifierFlags(propNode));
263+
});
264+
});

tests/baselines/reference/api/typescript.d.ts

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4752,32 +4752,32 @@ declare namespace ts {
47524752
}
47534753
enum ModifierFlags {
47544754
None = 0,
4755-
Export = 1,
4756-
Ambient = 2,
4757-
Public = 4,
4758-
Private = 8,
4759-
Protected = 16,
4760-
Static = 32,
4761-
Readonly = 64,
4762-
Accessor = 128,
4763-
Abstract = 256,
4764-
Async = 512,
4765-
Default = 1024,
4766-
Const = 2048,
4767-
HasComputedJSDocModifiers = 4096,
4768-
Deprecated = 8192,
4769-
Override = 16384,
4770-
In = 32768,
4771-
Out = 65536,
4772-
Decorator = 131072,
4755+
Public = 1,
4756+
Private = 2,
4757+
Protected = 4,
4758+
Readonly = 8,
4759+
Override = 16,
4760+
Export = 32,
4761+
Abstract = 64,
4762+
Ambient = 128,
4763+
Static = 256,
4764+
Accessor = 512,
4765+
Async = 1024,
4766+
Default = 2048,
4767+
Const = 4096,
4768+
In = 8192,
4769+
Out = 16384,
4770+
Decorator = 32768,
4771+
Deprecated = 65536,
4772+
HasComputedJSDocModifiers = 268435456,
47734773
HasComputedFlags = 536870912,
4774-
AccessibilityModifier = 28,
4775-
ParameterPropertyModifier = 16476,
4776-
NonPublicAccessibilityModifier = 24,
4777-
TypeScriptModifier = 117086,
4778-
ExportDefault = 1025,
4779-
All = 258047,
4780-
Modifier = 126975,
4774+
AccessibilityModifier = 7,
4775+
ParameterPropertyModifier = 31,
4776+
NonPublicAccessibilityModifier = 6,
4777+
TypeScriptModifier = 28895,
4778+
ExportDefault = 2080,
4779+
All = 131071,
4780+
Modifier = 98303,
47814781
}
47824782
enum JsxFlags {
47834783
None = 0,

0 commit comments

Comments
 (0)