-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Fixing namespace import debug failure #59004
Changes from 6 commits
e31bb29
c4d86b8
1347b9f
45af3f0
9e4a30a
e35b0f7
c0aaae4
dc452e8
d47ff25
ba4c3dd
fb453ee
ba364e8
b21b4a1
b23e6d8
cb06e8f
2a432e4
e3deb17
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -227,6 +227,7 @@ export interface ImportAdder { | |
addImportFromExportedSymbol: (exportedSymbol: Symbol, isValidTypeOnlyUseSite?: boolean, referenceImport?: ImportOrRequireAliasDeclaration) => void; | ||
addImportForNonExistentExport: (exportName: string, exportingFileName: string, exportKind: ExportKind, exportedMeanings: SymbolFlags, isImportUsageValidAsTypeOnly: boolean) => void; | ||
addImportForUnresolvedIdentifier: (context: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean) => void; | ||
addImportForExternalModuleSymbol: (symbol: Symbol, originalSymbol: Symbol, isValidTypeOnlyUseSite: boolean) => void; | ||
addVerbatimImport: (declaration: AnyImportOrRequireStatement | ImportOrRequireAliasDeclaration) => void; | ||
removeExistingImport: (declaration: ImportOrRequireAliasDeclaration) => void; | ||
writeFixes: (changeTracker: textChanges.ChangeTracker, oldFileQuotePreference?: QuotePreference) => void; | ||
|
@@ -255,7 +256,7 @@ function createImportAdderWorker(sourceFile: SourceFile | FutureSourceFile, prog | |
type NewImportsKey = `${0 | 1}|${string}`; | ||
/** Use `getNewImportEntry` for access */ | ||
const newImports = new Map<NewImportsKey, Mutable<ImportsCollection & { useRequire: boolean; }>>(); | ||
return { addImportFromDiagnostic, addImportFromExportedSymbol, writeFixes, hasFixes, addImportForUnresolvedIdentifier, addImportForNonExistentExport, removeExistingImport, addVerbatimImport }; | ||
return { addImportFromDiagnostic, addImportFromExportedSymbol, writeFixes, hasFixes, addImportForUnresolvedIdentifier, addImportForNonExistentExport, addImportForExternalModuleSymbol, removeExistingImport, addVerbatimImport }; | ||
|
||
function addVerbatimImport(declaration: AnyImportOrRequireStatement | ImportOrRequireAliasDeclaration) { | ||
verbatimImports.add(declaration); | ||
|
@@ -274,9 +275,10 @@ function createImportAdderWorker(sourceFile: SourceFile | FutureSourceFile, prog | |
} | ||
|
||
function addImportFromExportedSymbol(exportedSymbol: Symbol, isValidTypeOnlyUseSite?: boolean, referenceImport?: ImportOrRequireAliasDeclaration) { | ||
const checker = program.getTypeChecker(); | ||
const useRequire = shouldUseRequire(sourceFile, program); | ||
const moduleSymbol = Debug.checkDefined(exportedSymbol.parent); | ||
const symbolName = getNameForExportedSymbol(exportedSymbol, getEmitScriptTarget(compilerOptions)); | ||
const checker = program.getTypeChecker(); | ||
const symbol = checker.getMergedSymbol(skipAlias(exportedSymbol, checker)); | ||
const exportInfo = getAllExportInfoForSymbol(sourceFile, symbol, symbolName, moduleSymbol, /*preferCapitalized*/ false, program, host, preferences, cancellationToken); | ||
if (!exportInfo) { | ||
|
@@ -285,7 +287,6 @@ function createImportAdderWorker(sourceFile: SourceFile | FutureSourceFile, prog | |
Debug.assert(preferences.autoImportFileExcludePatterns?.length); | ||
return; | ||
} | ||
const useRequire = shouldUseRequire(sourceFile, program); | ||
let fix = getImportFixForSymbol(sourceFile, exportInfo, program, /*position*/ undefined, !!isValidTypeOnlyUseSite, useRequire, host, preferences); | ||
if (fix) { | ||
const localName = tryCast(referenceImport?.name, isIdentifier)?.text ?? symbolName; | ||
|
@@ -356,6 +357,24 @@ function createImportAdderWorker(sourceFile: SourceFile | FutureSourceFile, prog | |
} | ||
} | ||
|
||
function addImportForExternalModuleSymbol(symbol: Symbol, originalSymbol: Symbol, isValidTypeOnlyUseSite: boolean) { | ||
const useRequire = shouldUseRequire(sourceFile, program); | ||
if (originalSymbol.valueDeclaration) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this check for? When does an external module symbol not have a valueDeclaration? |
||
const moduleSpecifier = moduleSpecifiers.getLocalModuleSpecifierBetweenFileNames( | ||
sourceFile, | ||
originalSymbol.valueDeclaration.getSourceFile().fileName, | ||
compilerOptions, | ||
createModuleSpecifierResolutionHost(program, host), | ||
); | ||
const info: FixInfo = { | ||
fix: { kind: ImportFixKind.AddNew, importKind: ImportKind.Namespace, addAsTypeOnly: isValidTypeOnlyUseSite ? AddAsTypeOnly.Allowed : AddAsTypeOnly.NotAllowed, useRequire, moduleSpecifierKind: undefined, moduleSpecifier }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since there may be multiple different forms of import that can reference a whole module, you were asking about whether it’s ok to unconditionally coerce them into a namespace import. That might be fine, but it seems like it would make sense for this function to take an optional |
||
symbolName: symbol.name, | ||
errorIdentifierText: undefined, | ||
}; | ||
addImport(info); | ||
} | ||
} | ||
|
||
function removeExistingImport(declaration: ImportOrRequireAliasDeclaration) { | ||
if (declaration.kind === SyntaxKind.ImportClause) { | ||
Debug.assertIsDefined(declaration.name, "ImportClause should have a name if it's being removed"); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1131,14 +1131,22 @@ export function getExistingLocals(sourceFile: SourceFile, statements: readonly S | |
const declaration = importFromModuleSpecifier(moduleSpecifier); | ||
if ( | ||
isImportDeclaration(declaration) && declaration.importClause && | ||
declaration.importClause.namedBindings && isNamedImports(declaration.importClause.namedBindings) | ||
declaration.importClause.namedBindings | ||
) { | ||
for (const e of declaration.importClause.namedBindings.elements) { | ||
const symbol = checker.getSymbolAtLocation(e.propertyName || e.name); | ||
if (isNamespaceImport(declaration.importClause.namedBindings)) { | ||
const symbol = checker.getSymbolAtLocation(declaration.importClause.namedBindings.name); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there’s no need for |
||
if (symbol) { | ||
existingLocals.add(skipAlias(symbol, checker)); | ||
} | ||
} | ||
else if (isNamedImports(declaration.importClause.namedBindings)) { | ||
for (const e of declaration.importClause.namedBindings.elements) { | ||
const symbol = checker.getSymbolAtLocation(e.propertyName || e.name); | ||
if (symbol) { | ||
existingLocals.add(skipAlias(symbol, checker)); | ||
} | ||
} | ||
} | ||
} | ||
if (isVariableDeclarationInitializedToRequire(declaration.parent) && isObjectBindingPattern(declaration.parent.name)) { | ||
for (const e of declaration.parent.name.elements) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
symbol
/originalSymbol
are confusing names here. It looks likeoriginalSymbol
is the actual module symbol, andsymbol
is just an existing alias for the module that’s only being used to see what name to use. Instead, try just passing in the module symbol and the name you want to use?