Skip to content

Allow unexported local type aliases to be displayed in quickinfo. (#13095) #23638

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2680,8 +2680,8 @@ namespace ts {
return false;
}

function isTypeSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node): boolean {
const access = isSymbolAccessible(typeSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false);
function isTypeSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node, acceptLocal = false): boolean {
const access = isSymbolAccessible(typeSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false, acceptLocal);
return access.accessibility === SymbolAccessibility.Accessible;
}

Expand All @@ -2698,7 +2698,7 @@ namespace ts {
* @param meaning a SymbolFlags to check if such meaning of the symbol is accessible
* @param shouldComputeAliasToMakeVisible a boolean value to indicate whether to return aliases to be mark visible in case the symbol is accessible
*/
function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean): SymbolAccessibilityResult {
function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean, acceptLocal = false): SymbolAccessibilityResult {
if (symbol && enclosingDeclaration && !(symbol.flags & SymbolFlags.TypeParameter)) {
const initialSymbol = symbol;
let meaningToLook = meaning;
Expand All @@ -2708,6 +2708,11 @@ namespace ts {
if (accessibleSymbolChain) {
const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible);
if (!hasAccessibleDeclarations) {
if (acceptLocal) {
return {
accessibility: SymbolAccessibility.Accessible,
};
}
return {
accessibility: SymbolAccessibility.NotAccessible,
errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
Expand Down Expand Up @@ -3069,7 +3074,8 @@ namespace ts {
// Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter.
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
}
if (!inTypeAlias && type.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration))) {
if (!inTypeAlias && type.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope ||
isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, !!(context.flags & NodeBuilderFlags.UseLocalAliases)))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used by the declaration emitter, in addition to quick info and signature help, and I don't see any checks actually accounting for the enclosing declaration context, which worries me. Additionally, given that we have a UseAliasDefinedOutsideCurrentScope flag, I'm led to believe that one would believe that this should be the default behavior! However that may have to wait for #23351 though, which may, incidentally, subsume this. Will have to test.

const name = symbolToTypeReferenceName(type.aliasSymbol);
const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context);
return createTypeReferenceNode(name, typeArgumentNodes);
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3016,7 +3016,7 @@ namespace ts {
WriteArrayAsGenericType = 1 << 1, // Write Array<T> instead T[]
// empty space
UseStructuralFallback = 1 << 3, // When an alias cannot be named by its symbol, rather than report an error, fallback to a structural printout if possible
// empty space
UseLocalAliases = 1 << 4, // Write aliases that are in scope locally even if they are not exported.
WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature
UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
UseOnlyExternalAliasing = 1 << 7, // Only use external aliases for a symbol
Expand Down Expand Up @@ -3053,7 +3053,7 @@ namespace ts {
WriteArrayAsGenericType = 1 << 1, // Write Array<T> instead T[]
// hole because there's a hole in node builder flags
UseStructuralFallback = 1 << 3, // When an alias cannot be named by its symbol, rather than report an error, fallback to a structural printout if possible
// hole because there's a hole in node builder flags
UseLocalAliases = 1 << 4, // Write aliases that are in scope locally even if they are not exported.
WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature
UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
// hole because `UseOnlyExternalAliasing` is here in node builder flags, but functions which take old flags use `SymbolFormatFlags` instead
Expand Down Expand Up @@ -3084,7 +3084,7 @@ namespace ts {
NodeBuilderFlagsMask =
NoTruncation | WriteArrayAsGenericType | UseStructuralFallback | WriteTypeArgumentsOfSignature |
UseFullyQualifiedType | SuppressAnyReturnType | MultilineObjectLiterals | WriteClassExpressionAsTypeLiteral |
UseTypeOfFunction | OmitParameterModifiers | UseAliasDefinedOutsideCurrentScope | AllowUniqueESSymbolType | InTypeAlias,
UseTypeOfFunction | OmitParameterModifiers | UseAliasDefinedOutsideCurrentScope | AllowUniqueESSymbolType | InTypeAlias | UseLocalAliases,
}

export const enum SymbolFormatFlags {
Expand Down
4 changes: 2 additions & 2 deletions src/services/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1385,7 +1385,7 @@ namespace ts {

export function typeToDisplayParts(typechecker: TypeChecker, type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] {
return mapToDisplayParts(writer => {
typechecker.writeType(type, enclosingDeclaration, flags | TypeFormatFlags.MultilineObjectLiterals, writer);
typechecker.writeType(type, enclosingDeclaration, flags | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.UseLocalAliases, writer);
});
}

Expand All @@ -1396,7 +1396,7 @@ namespace ts {
}

export function signatureToDisplayParts(typechecker: TypeChecker, signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] {
flags |= TypeFormatFlags.UseAliasDefinedOutsideCurrentScope | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.WriteTypeArgumentsOfSignature | TypeFormatFlags.OmitParameterModifiers;
flags |= TypeFormatFlags.UseAliasDefinedOutsideCurrentScope | TypeFormatFlags.UseLocalAliases | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.WriteTypeArgumentsOfSignature | TypeFormatFlags.OmitParameterModifiers;
return mapToDisplayParts(writer => {
typechecker.writeSignature(signature, enclosingDeclaration, flags, /*signatureKind*/ undefined, writer);
});
Expand Down
4 changes: 3 additions & 1 deletion tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1848,6 +1848,7 @@ declare namespace ts {
NoTruncation = 1,
WriteArrayAsGenericType = 2,
UseStructuralFallback = 8,
UseLocalAliases = 16,
WriteTypeArgumentsOfSignature = 32,
UseFullyQualifiedType = 64,
UseOnlyExternalAliasing = 128,
Expand Down Expand Up @@ -1876,6 +1877,7 @@ declare namespace ts {
NoTruncation = 1,
WriteArrayAsGenericType = 2,
UseStructuralFallback = 8,
UseLocalAliases = 16,
WriteTypeArgumentsOfSignature = 32,
UseFullyQualifiedType = 64,
SuppressAnyReturnType = 256,
Expand All @@ -1892,7 +1894,7 @@ declare namespace ts {
InFirstTypeArgument = 4194304,
InTypeAlias = 8388608,
/** @deprecated */ WriteOwnNameForAnyLike = 0,
NodeBuilderFlagsMask = 9469291
NodeBuilderFlagsMask = 9469307
}
enum SymbolFormatFlags {
None = 0,
Expand Down
4 changes: 3 additions & 1 deletion tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1848,6 +1848,7 @@ declare namespace ts {
NoTruncation = 1,
WriteArrayAsGenericType = 2,
UseStructuralFallback = 8,
UseLocalAliases = 16,
WriteTypeArgumentsOfSignature = 32,
UseFullyQualifiedType = 64,
UseOnlyExternalAliasing = 128,
Expand Down Expand Up @@ -1876,6 +1877,7 @@ declare namespace ts {
NoTruncation = 1,
WriteArrayAsGenericType = 2,
UseStructuralFallback = 8,
UseLocalAliases = 16,
WriteTypeArgumentsOfSignature = 32,
UseFullyQualifiedType = 64,
SuppressAnyReturnType = 256,
Expand All @@ -1892,7 +1894,7 @@ declare namespace ts {
InFirstTypeArgument = 4194304,
InTypeAlias = 8388608,
/** @deprecated */ WriteOwnNameForAnyLike = 0,
NodeBuilderFlagsMask = 9469291
NodeBuilderFlagsMask = 9469307
}
enum SymbolFormatFlags {
None = 0,
Expand Down
35 changes: 35 additions & 0 deletions tests/cases/fourslash/quickInfoLocalTypeAliases.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/// <reference path="fourslash.ts" />

// @Filename: fileA.ts
//// type LocalAlias<T> = {a: T}
//// const var/*0*/1: LocalAlias<string>
//// export type ExpAlias<T> = {b: T}
//// const var/*1*/2: ExpAlias<string>
//// export declare function doSomething<T>(arg: T): ExpAlias<T>

// @Filename: fileB.ts
//// import { doSomething, ExpAlias } from "./fileA";
//// type FileBAlias<T> = {c: T}
//// declare const fba: FileBAlias<string>
//// const res/*2*/ult = doSomething(fba);

// @Filename: GH18754.ts
//// import "nothing"
//// type A/*3*/A = { tag: 'a', p/*4*/a: AL/*5*/L}
//// type BB = { tag: 'b', pb: ALL}
//// type ALL = AA | BB
//// declare var b/*6*/b: B/*7*/B
//// declare let a/*8*/ll: A/*9*/LL

verify.quickInfos({
0: "const var1: LocalAlias<string>",
1: "const var2: ExpAlias<string>",
2: "const result: ExpAlias<FileBAlias<string>>",
3: 'type AA = {\n tag: "a";\n pa: ALL;\n}',
4: "(property) pa: ALL",
5: "type ALL = AA | BB",
6: "var bb: BB",
7: 'type BB = {\n tag: "b";\n pb: ALL;\n}',
8: "let all: ALL",
9: "type ALL = AA | BB",
});