From eb88ca58f3c68d7c602beb0e2fda63077e8b688d Mon Sep 17 00:00:00 2001 From: Mark Pearce Date: Fri, 28 Jul 2023 14:57:28 -0300 Subject: [PATCH] Fixes small hover issues (#860) * Fixes small hover issues * Lint fixes --- src/bscPlugin/hover/HoverProcessor.spec.ts | 27 ++++++++++++++++++++++ src/bscPlugin/hover/HoverProcessor.ts | 8 +++++-- src/interfaces.ts | 1 + src/util.ts | 7 ++++-- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/bscPlugin/hover/HoverProcessor.spec.ts b/src/bscPlugin/hover/HoverProcessor.spec.ts index 0d93d8066..ffb4d16aa 100644 --- a/src/bscPlugin/hover/HoverProcessor.spec.ts +++ b/src/bscPlugin/hover/HoverProcessor.spec.ts @@ -376,5 +376,32 @@ describe('HoverProcessor', () => { expect(hover?.range).to.eql(util.createRange(6, 26, 6, 34)); expect(hover?.contents).to.eql([fence('someFunc as function')]); }); + + it('keeps unresolved types as type names', () => { + const file = program.setFile('source/main.bs', ` + sub doSomething(thing as UnknownType) + print thing + end sub + `); + program.validate(); + // print thi|ng + let hover = program.getHover(file.srcPath, util.createPosition(2, 30))[0]; + expect(hover?.range).to.eql(util.createRange(2, 26, 2, 31)); + expect(hover?.contents).eql([fence('thing as UnknownType')]); + }); + + it('says members on dynamic are dynamic', () => { + const file = program.setFile('source/main.bs', ` + sub doSomething(thing) + print thing.member + end sub + `); + program.validate(); + + // print thing.mem|ber + let hover = program.getHover(file.srcPath, util.createPosition(2, 36))[0]; + expect(hover?.range).to.eql(util.createRange(2, 32, 2, 38)); + expect(hover?.contents).eql([fence('member as dynamic')]); + }); }); }); diff --git a/src/bscPlugin/hover/HoverProcessor.ts b/src/bscPlugin/hover/HoverProcessor.ts index e43b2a8ed..3e9af1b80 100644 --- a/src/bscPlugin/hover/HoverProcessor.ts +++ b/src/bscPlugin/hover/HoverProcessor.ts @@ -154,17 +154,21 @@ export class HoverProcessor { const typeFlag = isInTypeExpression ? SymbolTypeFlag.typetime : SymbolTypeFlag.runtime; const typeChain: TypeChainEntry[] = []; const exprType = expression.getType({ flags: typeFlag, typeChain: typeChain }); + const processedTypeChain = util.processTypeChain(typeChain); const fullName = processedTypeChain.fullNameOfItem || token.text; const useCustomTypeHover = isInTypeExpression || expression?.findAncestor(isNewExpression); - let hoverContent = fence(`${fullName} as ${exprType.toString()}`); + + // if the type chain has dynamic in it, then just say the token text + const exprNameString = !processedTypeChain.containsDynamic ? fullName : token.text; + + let hoverContent = fence(`${exprNameString} as ${exprType.toString()}`); if (isTypedFunctionType(exprType)) { exprType.setName(fullName); hoverContent = this.getFunctionTypeHover(token, expression, exprType, scope); } else if (useCustomTypeHover && (isClassType(exprType) || isInterfaceType(exprType))) { hoverContent = this.getCustomTypeHover(exprType, scope); } - hoverContents.push(hoverContent); } finally { diff --git a/src/interfaces.ts b/src/interfaces.ts index ad5786885..db2fad279 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -498,5 +498,6 @@ export interface TypeChainProcessResult { fullNameOfItem: string; fullChainName: string; range: Range; + containsDynamic: boolean; } diff --git a/src/util.ts b/src/util.ts index 9fb02f151..0ef33545d 100644 --- a/src/util.ts +++ b/src/util.ts @@ -24,7 +24,7 @@ import type { CallExpression, CallfuncExpression, DottedGetExpression, FunctionP import { Logger, LogLevel } from './Logger'; import type { Identifier, Locatable, Token } from './lexer/Token'; import { TokenKind } from './lexer/TokenKind'; -import { isBooleanType, isBrsFile, isCallExpression, isCallfuncExpression, isDottedGetExpression, isDoubleType, isDynamicType, isExpression, isFloatType, isIndexedGetExpression, isIntegerType, isInvalidType, isLongIntegerType, isStringType, isTypeExpression, isVariableExpression, isXmlAttributeGetExpression, isXmlFile } from './astUtils/reflection'; +import { isBooleanType, isBrsFile, isCallExpression, isCallfuncExpression, isDottedGetExpression, isDoubleType, isDynamicType, isExpression, isFloatType, isIndexedGetExpression, isIntegerType, isInvalidType, isLongIntegerType, isReferenceType, isStringType, isTypeExpression, isVariableExpression, isXmlAttributeGetExpression, isXmlFile } from './astUtils/reflection'; import { WalkMode } from './astUtils/visitors'; import { SourceNode } from 'source-map'; import * as requireRelative from 'require-relative'; @@ -1673,6 +1673,7 @@ export class Util { let previousTypeName = ''; let parentTypeName = ''; let errorRange: Range; + let containsDynamic = false; for (let i = 0; i < typeChain.length; i++) { const chainItem = typeChain[i]; if (i > 0) { @@ -1683,6 +1684,7 @@ export class Util { fullErrorName = previousTypeName ? `${previousTypeName}.${chainItem.name}` : chainItem.name; previousTypeName = chainItem.type.toString(); itemName = chainItem.name; + containsDynamic = containsDynamic || (isDynamicType(chainItem.type) && !isReferenceType(chainItem.type)); if (!chainItem.isResolved) { errorRange = chainItem.range; break; @@ -1693,7 +1695,8 @@ export class Util { itemParentTypeName: parentTypeName, fullNameOfItem: fullErrorName, fullChainName: fullChainName, - range: errorRange + range: errorRange, + containsDynamic: containsDynamic }; } }