Merge branch 'master' into colectomy

This commit is contained in:
Daniel Rosenwasser 2014-10-28 12:16:58 -07:00
commit 32d22ba789
33 changed files with 597 additions and 319 deletions

View File

@ -38,6 +38,7 @@ module ts {
getFullWidth(): number;
getLeadingTriviaWidth(sourceFile?: SourceFile): number;
getFullText(sourceFile?: SourceFile): string;
getText(sourceFile?: SourceFile): string;
getFirstToken(sourceFile?: SourceFile): Node;
getLastToken(sourceFile?: SourceFile): Node;
}
@ -130,6 +131,10 @@ module ts {
return (sourceFile || this.getSourceFile()).text.substring(this.pos, this.end);
}
public getText(sourceFile?: SourceFile): string {
return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd());
}
private addSyntheticNodes(nodes: Node[], pos: number, end: number): number {
scanner.setTextPos(pos);
while (pos < end) {
@ -1287,7 +1292,6 @@ module ts {
position: number; // position in the file where the completion was requested
entries: CompletionEntry[]; // entries for this completion
symbols: Map<Symbol>; // symbols by entry name map
location: Node; // the node where the completion was requested
typeChecker: TypeChecker; // the typeChecker used to generate this completion
}
@ -1957,21 +1961,21 @@ module ts {
}
function isRightSideOfPropertyAccess(node: Node) {
return node.parent.kind === SyntaxKind.PropertyAccess && (<PropertyAccess>node.parent).right === node;
return node && node.parent && node.parent.kind === SyntaxKind.PropertyAccess && (<PropertyAccess>node.parent).right === node;
}
function isCallExpressionTarget(node: Node): boolean {
if (isRightSideOfPropertyAccess(node)) {
node = node.parent;
}
return node.parent.kind === SyntaxKind.CallExpression && (<CallExpression>node.parent).func === node;
return node && node.parent && node.parent.kind === SyntaxKind.CallExpression && (<CallExpression>node.parent).func === node;
}
function isNewExpressionTarget(node: Node): boolean {
if (isRightSideOfPropertyAccess(node)) {
node = node.parent;
}
return node.parent.kind === SyntaxKind.NewExpression && (<CallExpression>node.parent).func === node;
return node && node.parent && node.parent.kind === SyntaxKind.NewExpression && (<CallExpression>node.parent).func === node;
}
function isNameOfModuleDeclaration(node: Node) {
@ -2014,6 +2018,37 @@ module ts {
(node.parent.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>node.parent).externalModuleName === node));
}
/** Returns true if the position is within a comment */
function isInsideComment(sourceFile: SourceFile, token: Node, position: number): boolean {
// The position has to be: 1. in the leading trivia (before token.getStart()), and 2. within a comment
return position <= token.getStart(sourceFile) &&
(isInsideCommentRange(getTrailingCommentRanges(sourceFile.text, token.getFullStart())) ||
isInsideCommentRange(getLeadingCommentRanges(sourceFile.text, token.getFullStart())));
function isInsideCommentRange(comments: CommentRange[]): boolean {
return forEach(comments, comment => {
// either we are 1. completely inside the comment, or 2. at the end of the comment
if (comment.pos < position && position < comment.end) {
return true;
}
else if (position === comment.end) {
var text = sourceFile.text;
var width = comment.end - comment.pos;
// is single line comment or just /*
if (width <= 2 || text.charCodeAt(comment.pos + 1) === CharacterCodes.slash) {
return true;
}
else {
// is unterminated multi-line comment
return !(text.charCodeAt(comment.end - 1) === CharacterCodes.slash &&
text.charCodeAt(comment.end - 2) === CharacterCodes.asterisk);
}
}
return false;
});
}
}
enum SemanticMeaning {
None = 0x0,
Value = 0x1,
@ -2317,6 +2352,135 @@ module ts {
}
function getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) {
synchronizeHostData();
filename = TypeScript.switchToForwardSlashes(filename);
var sourceFile = getSourceFile(filename);
var currentToken = getTokenAtPosition(sourceFile, position);
// Completion not allowed inside comments, bail out if this is the case
if (isInsideComment(sourceFile, currentToken, position)) {
host.log("Returning an empty list because completion was inside a comment.");
return undefined;
}
// The decision to provide completion depends on the previous token, so find it
// Note: previousToken can be undefined if we are the beginning of the file
var previousToken = findPrecedingToken(position, sourceFile);
// The caret is at the end of an identifier; this is a partial identifier that we want to complete: e.g. a.toS|
// Skip this partial identifier to the previous token
if (previousToken && position <= previousToken.end && previousToken.kind === SyntaxKind.Identifier) {
previousToken = findPrecedingToken(previousToken.pos, sourceFile);
}
// Check if this is a valid completion location
if (previousToken && isCompletionListBlocker(previousToken)) {
host.log("Returning an empty list because completion was requested in an invalid position.");
return undefined;
}
// Find the node where completion is requested on, in the case of a completion after a dot, it is the member access expression
// other wise, it is a request for all visible symbols in the scope, and the node is the current location
var node: Node;
var isRightOfDot: boolean;
if (previousToken && previousToken.kind === SyntaxKind.DotToken &&
(previousToken.parent.kind === SyntaxKind.PropertyAccess || previousToken.parent.kind === SyntaxKind.QualifiedName)) {
node = (<PropertyAccess>previousToken.parent).left;
isRightOfDot = true;
}
else {
node = currentToken;
isRightOfDot = false;
}
// Clear the current activeCompletionSession for this session
activeCompletionSession = {
filename: filename,
position: position,
entries: [],
symbols: {},
typeChecker: typeInfoResolver
};
// Populate the completion list
if (isRightOfDot) {
// Right of dot member completion list
var symbols: Symbol[] = [];
isMemberCompletion = true;
if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccess) {
var symbol = typeInfoResolver.getSymbolInfo(node);
// This is an alias, follow what it aliases
if (symbol && symbol.flags & SymbolFlags.Import) {
symbol = typeInfoResolver.getAliasedSymbol(symbol);
}
if (symbol && symbol.flags & SymbolFlags.HasExports) {
// Extract module or enum members
forEachValue(symbol.exports, symbol => {
if (typeInfoResolver.isValidPropertyAccess(<PropertyAccess>(node.parent), symbol.name)) {
symbols.push(symbol);
}
});
}
}
var type = typeInfoResolver.getTypeOfNode(node);
if (type) {
// Filter private properties
forEach(type.getApparentProperties(), symbol => {
if (typeInfoResolver.isValidPropertyAccess(<PropertyAccess>(node.parent), symbol.name)) {
symbols.push(symbol);
}
});
}
getCompletionEntriesFromSymbols(symbols, activeCompletionSession);
}
else {
var containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion(previousToken);
if (containingObjectLiteral) {
// Object literal expression, look up possible property names from contextual type
isMemberCompletion = true;
var contextualType = typeInfoResolver.getContextualType(containingObjectLiteral);
if (!contextualType) {
return undefined;
}
var contextualTypeMembers = typeInfoResolver.getPropertiesOfType(contextualType);
if (contextualTypeMembers && contextualTypeMembers.length > 0) {
// Add filtered items to the completion list
var filteredMembers = filterContextualMembersList(contextualTypeMembers, containingObjectLiteral.properties);
getCompletionEntriesFromSymbols(filteredMembers, activeCompletionSession);
}
}
else {
// Get scope members
isMemberCompletion = false;
/// TODO filter meaning based on the current context
var symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Import;
var symbols = typeInfoResolver.getSymbolsInScope(node, symbolMeanings);
getCompletionEntriesFromSymbols(symbols, activeCompletionSession);
}
}
// Add keywords if this is not a member completion list
if (!isMemberCompletion) {
Array.prototype.push.apply(activeCompletionSession.entries, keywordCompletions);
}
return {
isMemberCompletion: isMemberCompletion,
entries: activeCompletionSession.entries
};
function getCompletionEntriesFromSymbols(symbols: Symbol[], session: CompletionSession): void {
forEach(symbols, symbol => {
var entry = createCompletionEntry(symbol, session.typeChecker);
@ -2327,40 +2491,47 @@ module ts {
});
}
function isCompletionListBlocker(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean {
// We shouldn't be getting a position that is outside the file because
// isEntirelyInsideComment can't handle when the position is out of bounds,
// callers should be fixed, however we should be resilient to bad inputs
// so we return true (this position is a blocker for getting completions)
if (position < 0 || position > TypeScript.fullWidth(sourceUnit)) {
return true;
}
// This method uses Fidelity completely. Some information can be reached using the AST, but not everything.
return TypeScript.Syntax.isEntirelyInsideComment(sourceUnit, position) ||
TypeScript.Syntax.isEntirelyInStringOrRegularExpressionLiteral(sourceUnit, position) ||
isIdentifierDefinitionLocation(sourceUnit, position) ||
isRightOfIllegalDot(sourceUnit, position);
function isCompletionListBlocker(previousToken: Node): boolean {
return isInStringOrRegularExpressionLiteral(previousToken) ||
isIdentifierDefinitionLocation(previousToken) ||
isRightOfIllegalDot(previousToken);
}
function getContainingObjectLiteralApplicableForCompletion(sourceUnit: TypeScript.SourceUnitSyntax, position: number): TypeScript.ISyntaxElement {
function isInStringOrRegularExpressionLiteral(previousToken: Node): boolean {
if (previousToken.kind === SyntaxKind.StringLiteral) {
// The position has to be either: 1. entirely within the token text, or
// 2. at the end position, and the string literal is not terminated
var start = previousToken.getStart();
var end = previousToken.getEnd();
if (start < position && position < end) {
return true;
}
else if (position === end) {
var width = end - start;
var text = previousToken.getSourceFile().text;
return width <= 1 ||
text.charCodeAt(start) !== text.charCodeAt(end - 1) ||
text.charCodeAt(end - 2) === CharacterCodes.backslash;
}
}
else if (previousToken.kind === SyntaxKind.RegularExpressionLiteral) {
return previousToken.getStart() < position && position < previousToken.getEnd();
}
return false;
}
function getContainingObjectLiteralApplicableForCompletion(previousToken: Node): ObjectLiteral {
// The locations in an object literal expression that are applicable for completion are property name definition locations.
var previousToken = getNonIdentifierCompleteTokenOnLeft(sourceUnit, position);
if (previousToken) {
var parent = previousToken.parent;
switch (previousToken.kind()) {
case TypeScript.SyntaxKind.OpenBraceToken: // var x = { |
case TypeScript.SyntaxKind.CommaToken: // var x = { a: 0, |
if (parent && parent.kind() === TypeScript.SyntaxKind.SeparatedList) {
parent = parent.parent;
switch (previousToken.kind) {
case SyntaxKind.OpenBraceToken: // var x = { |
case SyntaxKind.CommaToken: // var x = { a: 0, |
if (parent && parent.kind === SyntaxKind.ObjectLiteral) {
return <ObjectLiteral>parent;
}
if (parent && parent.kind() === TypeScript.SyntaxKind.ObjectLiteralExpression) {
return parent;
}
break;
}
}
@ -2368,47 +2539,71 @@ module ts {
return undefined;
}
function isIdentifierDefinitionLocation(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean {
var positionedToken = getNonIdentifierCompleteTokenOnLeft(sourceUnit, position);
function isFunction(kind: SyntaxKind): boolean {
switch (kind) {
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.Method:
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
return true;
}
return false;
}
if (positionedToken) {
var containingNodeKind = TypeScript.Syntax.containingNode(positionedToken) && TypeScript.Syntax.containingNode(positionedToken).kind();
switch (positionedToken.kind()) {
case TypeScript.SyntaxKind.CommaToken:
return containingNodeKind === TypeScript.SyntaxKind.ParameterList ||
containingNodeKind === TypeScript.SyntaxKind.VariableDeclaration ||
containingNodeKind === TypeScript.SyntaxKind.EnumDeclaration; // enum { foo, |
function isIdentifierDefinitionLocation(previousToken: Node): boolean {
if (previousToken) {
var containingNodeKind = previousToken.parent.kind;
switch (previousToken.kind) {
case SyntaxKind.CommaToken:
return containingNodeKind === SyntaxKind.VariableDeclaration ||
containingNodeKind === SyntaxKind.VariableStatement ||
containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { foo, |
isFunction(containingNodeKind);
case TypeScript.SyntaxKind.OpenParenToken:
return containingNodeKind === TypeScript.SyntaxKind.ParameterList ||
containingNodeKind === TypeScript.SyntaxKind.CatchClause;
case SyntaxKind.OpenParenToken:
return containingNodeKind === SyntaxKind.CatchBlock ||
isFunction(containingNodeKind);
case TypeScript.SyntaxKind.OpenBraceToken:
return containingNodeKind === TypeScript.SyntaxKind.EnumDeclaration; // enum { |
case SyntaxKind.OpenBraceToken:
return containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { |
containingNodeKind === SyntaxKind.InterfaceDeclaration; // interface a { |
case TypeScript.SyntaxKind.PublicKeyword:
case TypeScript.SyntaxKind.PrivateKeyword:
case TypeScript.SyntaxKind.StaticKeyword:
case TypeScript.SyntaxKind.DotDotDotToken:
return containingNodeKind === TypeScript.SyntaxKind.Parameter;
case SyntaxKind.SemicolonToken:
return containingNodeKind === SyntaxKind.Property &&
previousToken.parent.parent.kind === SyntaxKind.InterfaceDeclaration; // interface a { f; |
case TypeScript.SyntaxKind.ClassKeyword:
case TypeScript.SyntaxKind.ModuleKeyword:
case TypeScript.SyntaxKind.EnumKeyword:
case TypeScript.SyntaxKind.InterfaceKeyword:
case TypeScript.SyntaxKind.FunctionKeyword:
case TypeScript.SyntaxKind.VarKeyword:
case TypeScript.SyntaxKind.GetKeyword:
case TypeScript.SyntaxKind.SetKeyword:
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.StaticKeyword:
case SyntaxKind.DotDotDotToken:
return containingNodeKind === SyntaxKind.Parameter;
case SyntaxKind.ClassKeyword:
case SyntaxKind.ModuleKeyword:
case SyntaxKind.EnumKeyword:
case SyntaxKind.InterfaceKeyword:
case SyntaxKind.FunctionKeyword:
case SyntaxKind.VarKeyword:
case SyntaxKind.GetKeyword:
case SyntaxKind.SetKeyword:
return true;
}
// Previous token may have been a keyword that was converted to an identifier.
switch (positionedToken.text()) {
switch (previousToken.getText()) {
case "class":
case "interface":
case "enum":
case "module":
case "function":
case "var":
// TODO: add let and const
return true;
}
}
@ -2416,44 +2611,15 @@ module ts {
return false;
}
function getNonIdentifierCompleteTokenOnLeft(sourceUnit: TypeScript.SourceUnitSyntax, position: number): TypeScript.ISyntaxToken {
var positionedToken = TypeScript.Syntax.findCompleteTokenOnLeft(sourceUnit, position, /*includeSkippedTokens*/true);
if (positionedToken && position === TypeScript.end(positionedToken) && positionedToken.kind() == TypeScript.SyntaxKind.EndOfFileToken) {
// EndOfFile token is not interesting, get the one before it
positionedToken = TypeScript. previousToken(positionedToken, /*includeSkippedTokens*/true);
}
if (positionedToken && position === TypeScript.end(positionedToken) && positionedToken.kind() === TypeScript.SyntaxKind.IdentifierName) {
// The caret is at the end of an identifier, the decision to provide completion depends on the previous token
positionedToken = TypeScript.previousToken(positionedToken, /*includeSkippedTokens*/true);
}
return positionedToken;
}
function isRightOfIllegalDot(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean {
var positionedToken = getNonIdentifierCompleteTokenOnLeft(sourceUnit, position);
if (positionedToken) {
switch (positionedToken.kind()) {
case TypeScript.SyntaxKind.DotToken:
var leftOfDotPositionedToken = TypeScript.previousToken(positionedToken, /*includeSkippedTokens*/true);
return leftOfDotPositionedToken && leftOfDotPositionedToken.kind() === TypeScript.SyntaxKind.NumericLiteral;
case TypeScript.SyntaxKind.NumericLiteral:
var text = positionedToken.text();
return text.charAt(text.length - 1) === ".";
}
function isRightOfIllegalDot(previousToken: Node): boolean {
if (previousToken && previousToken.kind === SyntaxKind.NumericLiteral) {
var text = previousToken.getFullText();
return text.charAt(text.length - 1) === ".";
}
return false;
}
function isPunctuation(kind: SyntaxKind) {
return (SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation);
}
function filterContextualMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] {
if (!existingMembers || existingMembers.length === 0) {
return contextualMemberSymbols;
@ -2483,162 +2649,6 @@ module ts {
return filteredMembers;
}
synchronizeHostData();
filename = TypeScript.switchToForwardSlashes(filename);
var sourceFile = getSourceFile(filename);
var sourceUnit = sourceFile.getSourceUnit();
if (isCompletionListBlocker(sourceFile.getSyntaxTree().sourceUnit(), position)) {
host.log("Returning an empty list because completion was blocked.");
return null;
}
var node = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, position, /*useTrailingTriviaAsLimChar*/ true, /*forceInclusive*/ true);
if (node && node.kind() === TypeScript.SyntaxKind.IdentifierName &&
TypeScript.start(node) === TypeScript.end(node)) {
// Ignore missing name nodes
node = node.parent;
}
var isRightOfDot = false;
if (node &&
node.kind() === TypeScript.SyntaxKind.MemberAccessExpression &&
TypeScript.end((<TypeScript.MemberAccessExpressionSyntax>node).expression) < position) {
isRightOfDot = true;
node = (<TypeScript.MemberAccessExpressionSyntax>node).expression;
}
else if (node &&
node.kind() === TypeScript.SyntaxKind.QualifiedName &&
TypeScript.end((<TypeScript.QualifiedNameSyntax>node).left) < position) {
isRightOfDot = true;
node = (<TypeScript.QualifiedNameSyntax>node).left;
}
else if (node && node.parent &&
node.kind() === TypeScript.SyntaxKind.IdentifierName &&
node.parent.kind() === TypeScript.SyntaxKind.MemberAccessExpression &&
(<TypeScript.MemberAccessExpressionSyntax>node.parent).name === node) {
isRightOfDot = true;
node = (<TypeScript.MemberAccessExpressionSyntax>node.parent).expression;
}
else if (node && node.parent &&
node.kind() === TypeScript.SyntaxKind.IdentifierName &&
node.parent.kind() === TypeScript.SyntaxKind.QualifiedName &&
(<TypeScript.QualifiedNameSyntax>node.parent).right === node) {
isRightOfDot = true;
node = (<TypeScript.QualifiedNameSyntax>node.parent).left;
}
// TODO: this is a hack for now, we need a proper walking mechanism to verify that we have the correct node
var precedingToken = findTokenOnLeftOfPosition(sourceFile, TypeScript.end(node));
var mappedNode: Node;
if (!precedingToken) {
mappedNode = sourceFile;
}
else if (isPunctuation(precedingToken.kind)) {
mappedNode = precedingToken.parent;
}
else {
mappedNode = precedingToken;
}
Debug.assert(mappedNode, "Could not map a Fidelity node to an AST node");
// Get the completions
activeCompletionSession = {
filename: filename,
position: position,
entries: [],
symbols: {},
location: mappedNode,
typeChecker: typeInfoResolver
};
// Right of dot member completion list
if (isRightOfDot) {
var symbols: Symbol[] = [];
isMemberCompletion = true;
if (mappedNode.kind === SyntaxKind.Identifier || mappedNode.kind === SyntaxKind.QualifiedName || mappedNode.kind === SyntaxKind.PropertyAccess) {
var symbol = typeInfoResolver.getSymbolInfo(mappedNode);
// This is an alias, follow what it aliases
if (symbol && symbol.flags & SymbolFlags.Import) {
symbol = typeInfoResolver.getAliasedSymbol(symbol);
}
if (symbol && symbol.flags & SymbolFlags.HasExports) {
// Extract module or enum members
forEachValue(symbol.exports, symbol => {
if (typeInfoResolver.isValidPropertyAccess(<PropertyAccess>(mappedNode.parent), symbol.name)) {
symbols.push(symbol);
}
});
}
}
var type = typeInfoResolver.getTypeOfNode(mappedNode);
if (type) {
// Filter private properties
forEach(type.getApparentProperties(), symbol => {
if (typeInfoResolver.isValidPropertyAccess(<PropertyAccess>(mappedNode.parent), symbol.name)) {
symbols.push(symbol);
}
});
}
getCompletionEntriesFromSymbols(symbols, activeCompletionSession);
}
else {
var containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion(sourceFile.getSyntaxTree().sourceUnit(), position);
// Object literal expression, look up possible property names from contextual type
if (containingObjectLiteral) {
var objectLiteral = <ObjectLiteral>(mappedNode.kind === SyntaxKind.ObjectLiteral ? mappedNode : getAncestor(mappedNode, SyntaxKind.ObjectLiteral));
Debug.assert(objectLiteral);
isMemberCompletion = true;
var contextualType = typeInfoResolver.getContextualType(objectLiteral);
if (!contextualType) {
return undefined;
}
var contextualTypeMembers = typeInfoResolver.getPropertiesOfType(contextualType);
if (contextualTypeMembers && contextualTypeMembers.length > 0) {
// Add filtered items to the completion list
var filteredMembers = filterContextualMembersList(contextualTypeMembers, objectLiteral.properties);
getCompletionEntriesFromSymbols(filteredMembers, activeCompletionSession);
}
}
// Get scope members
else {
isMemberCompletion = false;
/// TODO filter meaning based on the current context
var symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Import;
var symbols = typeInfoResolver.getSymbolsInScope(mappedNode, symbolMeanings);
getCompletionEntriesFromSymbols(symbols, activeCompletionSession);
}
}
// Add keywords if this is not a member completion list
if (!isMemberCompletion) {
Array.prototype.push.apply(activeCompletionSession.entries, keywordCompletions);
}
return {
isMemberCompletion: isMemberCompletion,
entries: activeCompletionSession.entries
};
}
function getCompletionEntryDetails(filename: string, position: number, entryName: string): CompletionEntryDetails {
@ -2646,6 +2656,8 @@ module ts {
// in the getCompletionsAtPosition earlier
filename = TypeScript.switchToForwardSlashes(filename);
var sourceFile = getSourceFile(filename);
var session = activeCompletionSession;
// Ensure that the current active completion session is still valid for this request
@ -2662,7 +2674,8 @@ module ts {
// which is permissible given that it is backwards compatible; but really we should consider
// passing the meaning for the node so that we don't report that a suggestion for a value is an interface.
// We COULD also just do what 'getSymbolModifiers' does, which is to use the first declaration.
var displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getSourceFile(filename), session.location, session.typeChecker, session.location, SemanticMeaning.All);
var location = getTouchingPropertyName(sourceFile, position);
var displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getSourceFile(filename), location, session.typeChecker, location, SemanticMeaning.All);
return {
name: entryName,
kind: displayPartsDocumentationsAndSymbolKind.symbolKind,
@ -2824,14 +2837,24 @@ module ts {
var type = typeResolver.getTypeOfSymbol(symbol);
if (type) {
if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) {
// try get the call/construct signature from the type if it matches
var callExpression: CallExpression;
if (location.parent.kind === SyntaxKind.PropertyAccess && (<PropertyAccess>location.parent).right === location) {
if (location.parent && location.parent.kind === SyntaxKind.PropertyAccess) {
var right = (<PropertyAccess>location.parent).right;
// Either the location is on the right of a property access, or on the left and the right is missing
if (right === location || (right && right.kind === SyntaxKind.Missing)){
location = location.parent;
}
callExpression = <CallExpression>location.parent;
}
// try get the call/construct signature from the type if it matches
var callExpression: CallExpression;
if (location.kind === SyntaxKind.CallExpression || location.kind === SyntaxKind.NewExpression) {
callExpression = <CallExpression> location;
}
else if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) {
callExpression = <CallExpression>location.parent;
}
if (callExpression) {
var candidateSignatures: Signature[] = [];
signature = typeResolver.getResolvedSignature(callExpression, candidateSignatures);
if (!signature && candidateSignatures.length) {
@ -5132,16 +5155,7 @@ module ts {
// OK, we have found a match in the file. This is only an acceptable match if
// it is contained within a comment.
var token = getTokenAtPosition(sourceFile, matchPosition);
if (token.getStart() <= matchPosition && matchPosition < token.getEnd()) {
// match was within the token itself. Not in the comment. Keep searching
// descriptor.
continue;
}
// Looks to be within the trivia. See if we can find the comment containing it.
if (!getContainingComment(getTrailingCommentRanges(fileContents, token.getFullStart()), matchPosition) &&
!getContainingComment(getLeadingCommentRanges(fileContents, token.getFullStart()), matchPosition)) {
if (!isInsideComment(sourceFile, token, matchPosition)) {
continue;
}

View File

@ -95,11 +95,12 @@ module ts {
var child = current.getChildAt(i);
var start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile);
if (start <= position) {
if (position < child.getEnd()) {
var end = child.getEnd();
if (position < end || (position === end && child.kind === SyntaxKind.EndOfFileToken)) {
current = child;
continue outer;
}
else if (includeItemAtEndPosition && child.getEnd() === position) {
else if (includeItemAtEndPosition && end === position) {
var previousToken = findPrecedingToken(position, sourceFile, child);
if (previousToken && includeItemAtEndPosition(previousToken)) {
return previousToken;
@ -180,7 +181,7 @@ module ts {
for (var i = 0, len = children.length; i < len; ++i) {
var child = children[i];
if (nodeHasTokens(child)) {
if (position < child.end) {
if (position <= child.end) {
if (child.getStart(sourceFile) >= position) {
// actual start of the node is past the position - previous token should be at the end of previous child
var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i);

View File

@ -64,7 +64,7 @@ goTo.marker('7');
verify.quickInfoIs("(var) myvar: m1.m2.c", "");
goTo.marker('8');
verify.memberListContains("c", "class m1.m2.c", "class comment;");
verify.memberListContains("c", "(constructor) m1.m2.c(): m1.m2.c", "");
verify.memberListContains("i", "(var) m1.m2.i: m1.m2.c", "i");
goTo.file("commentsExternalModules_file1.ts");
@ -91,5 +91,5 @@ goTo.marker('14');
verify.quickInfoIs("(var) newVar: extMod.m1.m2.c", "");
goTo.marker('15');
verify.memberListContains("c", "class extMod.m1.m2.c", "class comment;");
verify.memberListContains("c", "(constructor) extMod.m1.m2.c(): extMod.m1.m2.c", "");
verify.memberListContains("i", "(var) extMod.m1.m2.i: extMod.m1.m2.c", "i");

View File

@ -74,7 +74,7 @@ goTo.marker('12');
verify.quickInfoIs("(var) lambddaNoVarComment: (a: number, b: number) => number", "");
goTo.marker('13');
verify.completionListContains('lambdaFoo', '(var) lambdaFoo: (a: number, b: number) => number', 'lamdaFoo var comment');
verify.completionListContains('lambdaFoo', '(var) lambdaFoo: (a: number, b: number) => number', '');
verify.completionListContains('lambddaNoVarComment', '(var) lambddaNoVarComment: (a: number, b: number) => number', '');
goTo.marker('14');

View File

@ -47,5 +47,5 @@ goTo.marker('9');
verify.quickInfoIs("(var) newVar: extMod.m1.m2.c", "");
goTo.marker('10');
verify.memberListContains("c", "class extMod.m1.m2.c", "class comment;");
verify.memberListContains("c", "(constructor) extMod.m1.m2.c(): extMod.m1.m2.c", "");
verify.memberListContains("i", "(var) extMod.m1.m2.i: extMod.m1.m2.c", "i");

View File

@ -223,7 +223,7 @@
goTo.marker('1');
verify.memberListContains("i1_p1", "(property) i1.i1_p1: number", "i1_p1");
verify.memberListContains("i1_f1", "(method) i1.i1_f1(): void", "i1_f1");
verify.memberListContains("i1_l1", "(property) i1.i1_l1: () => void", "i1_l1");
verify.memberListContains("i1_l1", "(property) i1.i1_l1: () => void", "");
verify.memberListContains("i1_nc_p1", "(property) i1.i1_nc_p1: number", "");
verify.memberListContains("i1_nc_f1", "(method) i1.i1_nc_f1(): void", "");
verify.memberListContains("i1_nc_l1", "(property) i1.i1_nc_l1: () => void", "");
@ -278,10 +278,10 @@ verify.memberListContains("i1_nc_f1", "(method) c1.i1_nc_f1(): void", "");
verify.memberListContains("i1_nc_l1", "(property) c1.i1_nc_l1: () => void", "");
verify.memberListContains("p1", "(property) c1.p1: number", "c1_p1");
verify.memberListContains("f1", "(method) c1.f1(): void", "c1_f1");
verify.memberListContains("l1", "(property) c1.l1: () => void", "c1_l1");
verify.memberListContains("l1", "(property) c1.l1: () => void", "");
verify.memberListContains("nc_p1", "(property) c1.nc_p1: number", "c1_nc_p1");
verify.memberListContains("nc_f1", "(method) c1.nc_f1(): void", "c1_nc_f1");
verify.memberListContains("nc_l1", "(property) c1.nc_l1: () => void", "c1_nc_l1");
verify.memberListContains("nc_l1", "(property) c1.nc_l1: () => void", "");
goTo.marker('7');
verify.currentSignatureHelpDocCommentIs("");
goTo.marker('8');
@ -321,7 +321,7 @@ verify.quickInfoIs("(property) c1.nc_l1: () => void", "");
goTo.marker('11');
verify.memberListContains("i1_p1", "(property) i1.i1_p1: number", "i1_p1");
verify.memberListContains("i1_f1", "(method) i1.i1_f1(): void", "i1_f1");
verify.memberListContains("i1_l1", "(property) i1.i1_l1: () => void", "i1_l1");
verify.memberListContains("i1_l1", "(property) i1.i1_l1: () => void", "");
verify.memberListContains("i1_nc_p1", "(property) i1.i1_nc_p1: number", "");
verify.memberListContains("i1_nc_f1", "(method) i1.i1_nc_f1(): void", "");
verify.memberListContains("i1_nc_l1", "(property) i1.i1_nc_l1: () => void", "");
@ -508,13 +508,13 @@ verify.completionListContains("c4_i", "(var) c4_i: c4", "");
goTo.marker('36');
verify.memberListContains("i2_p1", "(property) i2.i2_p1: number", "i2_p1");
verify.memberListContains("i2_f1", "(method) i2.i2_f1(): void", "i2_f1");
verify.memberListContains("i2_l1", "(property) i2.i2_l1: () => void", "i2_l1");
verify.memberListContains("i2_l1", "(property) i2.i2_l1: () => void", "");
verify.memberListContains("i2_nc_p1", "(property) i2.i2_nc_p1: number", "");
verify.memberListContains("i2_nc_f1", "(method) i2.i2_nc_f1(): void", "");
verify.memberListContains("i2_nc_l1", "(property) i2.i2_nc_l1: () => void", "");
verify.memberListContains("p1", "(property) i2.p1: number", "i2 p1");
verify.memberListContains("f1", "(method) i2.f1(): void", "i2 f1");
verify.memberListContains("l1", "(property) i2.l1: () => void", "i2 l1");
verify.memberListContains("l1", "(property) i2.l1: () => void", "");
verify.memberListContains("nc_p1", "(property) i2.nc_p1: number", "");
verify.memberListContains("nc_f1", "(method) i2.nc_f1(): void", "");
verify.memberListContains("nc_l1", "(property) i2.nc_l1: () => void", "");
@ -559,13 +559,13 @@ verify.quickInfoIs("(property) i2.nc_l1: () => void", "");
goTo.marker('41');
verify.memberListContains("i2_p1", "(property) i2.i2_p1: number", "i2_p1");
verify.memberListContains("i2_f1", "(method) i2.i2_f1(): void", "i2_f1");
verify.memberListContains("i2_l1", "(property) i2.i2_l1: () => void", "i2_l1");
verify.memberListContains("i2_l1", "(property) i2.i2_l1: () => void", "");
verify.memberListContains("i2_nc_p1", "(property) i2.i2_nc_p1: number", "");
verify.memberListContains("i2_nc_f1", "(method) i2.i2_nc_f1(): void", "");
verify.memberListContains("i2_nc_l1", "(property) i2.i2_nc_l1: () => void", "");
verify.memberListContains("p1", "(property) i3.p1: number", "i3 p1");
verify.memberListContains("f1", "(method) i3.f1(): void", "i3 f1");
verify.memberListContains("l1", "(property) i3.l1: () => void", "i3 l1");
verify.memberListContains("l1", "(property) i3.l1: () => void", "");
verify.memberListContains("nc_p1", "(property) i3.nc_p1: number", "");
verify.memberListContains("nc_f1", "(method) i3.nc_f1(): void", "");
verify.memberListContains("nc_l1", "(property) i3.nc_l1: () => void", "");
@ -606,13 +606,13 @@ verify.quickInfoIs("(property) i3.nc_l1: () => void", "");
goTo.marker('46');
verify.memberListContains("i2_p1", "(property) i2.i2_p1: number", "i2_p1");
verify.memberListContains("i2_f1", "(method) i2.i2_f1(): void", "i2_f1");
verify.memberListContains("i2_l1", "(property) i2.i2_l1: () => void", "i2_l1");
verify.memberListContains("i2_l1", "(property) i2.i2_l1: () => void", "");
verify.memberListContains("i2_nc_p1", "(property) i2.i2_nc_p1: number", "");
verify.memberListContains("i2_nc_f1", "(method) i2.i2_nc_f1(): void", "");
verify.memberListContains("i2_nc_l1", "(property) i2.i2_nc_l1: () => void", "");
verify.memberListContains("p1", "(property) i2.p1: number", "i2 p1");
verify.memberListContains("f1", "(method) i2.f1(): void", "i2 f1");
verify.memberListContains("l1", "(property) i2.l1: () => void", "i2 l1");
verify.memberListContains("l1", "(property) i2.l1: () => void", "");
verify.memberListContains("nc_p1", "(property) i2.nc_p1: number", "");
verify.memberListContains("nc_f1", "(method) i2.nc_f1(): void", "");
verify.memberListContains("nc_l1", "(property) i2.nc_l1: () => void", "");

View File

@ -235,7 +235,7 @@ verify.completionListContains("i3_i", "(var) i3_i: i3", "");
goTo.marker('41');
verify.quickInfoIs("(method) i3.f(a: number): string", "Function i3 f");
verify.memberListContains("f", "(method) i3.f(a: number): string", "Function i3 f");
verify.memberListContains("l", "(property) i3.l: (b: number) => string", "i3 l");
verify.memberListContains("l", "(property) i3.l: (b: number) => string", "");
verify.memberListContains("x", "(property) i3.x: number", "Comment i3 x");
verify.memberListContains("nc_f", "(method) i3.nc_f(a: number): string", "");
verify.memberListContains("nc_l", "(property) i3.nc_l: (b: number) => string", "");

View File

@ -125,7 +125,7 @@ verify.quickInfoIs("(var) myvar: m1.m2.c", "");
goTo.marker('8');
verify.quickInfoIs("(constructor) m1.m2.c(): m1.m2.c", "");
verify.memberListContains("c", "class m1.m2.c", "class comment;");
verify.memberListContains("c", "(constructor) m1.m2.c(): m1.m2.c", "");
verify.memberListContains("i", "(var) m1.m2.i: m1.m2.c", "i");
goTo.marker('9');
@ -138,7 +138,7 @@ verify.quickInfoIs("module m2.m3", "module comment of m2.m3");
goTo.marker('11');
verify.quickInfoIs("(constructor) m2.m3.c(): m2.m3.c", "");
verify.memberListContains("c", "class m2.m3.c", "Exported class comment");
verify.memberListContains("c", "(constructor) m2.m3.c(): m2.m3.c", "");
goTo.marker('12');
verify.completionListContains("m3", "module m3", "");
@ -153,8 +153,8 @@ verify.memberListContains("m5", "module m3.m4.m5");
verify.quickInfoIs("module m3.m4.m5", "module comment of m3.m4.m5");
goTo.marker('15');
verify.memberListContains("c", "class m3.m4.m5.c", "Exported class comment");
verify.quickInfoIs("(constructor) m3.m4.m5.c(): m3.m4.m5.c", "");
verify.memberListContains("c", "(constructor) m3.m4.m5.c(): m3.m4.m5.c", "");
goTo.marker('16');
verify.completionListContains("m4", "module m4", "");
@ -173,7 +173,7 @@ verify.memberListContains("m7", "module m4.m5.m6.m7");
verify.quickInfoIs("module m4.m5.m6.m7", "");
goTo.marker('20');
verify.memberListContains("c", "class m4.m5.m6.m7.c", "Exported class comment");
verify.memberListContains("c", "(constructor) m4.m5.m6.m7.c(): m4.m5.m6.m7.c", "");
verify.quickInfoIs("(constructor) m4.m5.m6.m7.c(): m4.m5.m6.m7.c", "");
goTo.marker('21');
@ -193,7 +193,7 @@ verify.memberListContains("m8", "module m5.m6.m7.m8");
verify.quickInfoIs("module m5.m6.m7.m8", "module m8 comment");
goTo.marker('25');
verify.memberListContains("c", "class m5.m6.m7.m8.c", "Exported class comment");
verify.memberListContains("c", "(constructor) m5.m6.m7.m8.c(): m5.m6.m7.m8.c", "");
verify.quickInfoIs("(constructor) m5.m6.m7.m8.c(): m5.m6.m7.m8.c", "");
goTo.marker('26');
@ -209,7 +209,7 @@ verify.memberListContains("m8", "module m6.m7.m8");
verify.quickInfoIs("module m6.m7.m8", "");
goTo.marker('29');
verify.memberListContains("c", "class m6.m7.m8.c", "Exported class comment");
verify.memberListContains("c", "(constructor) m6.m7.m8.c(): m6.m7.m8.c", "");
verify.quickInfoIs("(constructor) m6.m7.m8.c(): m6.m7.m8.c", "");
goTo.marker('30');
@ -225,7 +225,7 @@ verify.memberListContains("m9", "module m7.m8.m9");
verify.quickInfoIs("module m7.m8.m9", "module m9 comment");
goTo.marker('33');
verify.memberListContains("c", "class m7.m8.m9.c", "Exported class comment");
verify.memberListContains("c", "(constructor) m7.m8.m9.c(): m7.m8.m9.c", "");
verify.quickInfoIs("(constructor) m7.m8.m9.c(): m7.m8.m9.c", "");
goTo.marker('34');

View File

@ -594,11 +594,7 @@ goTo.marker('64q');
verify.quickInfoIs("(constructor) c5(b: string): c5 (+1 overload)", "c5 2");
goTo.marker('65');
//verify.completionListContains("c", "class c", "");
// the below check is wrong and it should show it as class but currently we have a bug for adding the parameters of ambient function in the symbol list
// eg declare function foo2(x: number);
// completion list here
verify.completionListContains("c", "(parameter) c: boolean", "");
verify.completionListContains("c", "class c", "");
verify.completionListContains("c1", "class c1", "");
verify.completionListContains("c2", "class c2", "");
verify.completionListContains("c3", "class c3", "");

View File

@ -0,0 +1,25 @@
/// <reference path='fourslash.ts' />
////// Outside the function
////declare function f1(a: number);/*1*/
////
////// inside the function
////declare function f2(b: number, b2 = /*2*/
////
////// Outside the function
////function f3(c: number) { }/*3*/
////
////// inside the function
////function f4(d: number) { /*4*/}
goTo.marker("1");
verify.not.completionListContains("a");
goTo.marker("2");
verify.completionListContains("b");
goTo.marker("3");
verify.not.completionListContains("c");
goTo.marker("4");
verify.completionListContains("d");

View File

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
////// Outside the function expression
////declare var f1: (a: number) => void; /*1*/
////
////declare var f1: (b: number, b2: /*2*/) => void;
goTo.marker("1");
verify.not.completionListContains("a");
goTo.marker("2");
verify.completionListContains("b");

View File

@ -0,0 +1,12 @@
/// <reference path='fourslash.ts' />
////// Outside the function expression
////var x1 = (a: number) => { }/*1*/;
////
////var x2 = (b: number) => {/*2*/ };
goTo.marker("1");
verify.not.completionListContains("a");
goTo.marker("2");
verify.completionListContains("b");

View File

@ -25,10 +25,10 @@ goTo.marker("dotOnNumberExrpressions1");
verify.completionListIsEmpty();
goTo.marker("dotOnNumberExrpressions2");
verify.completionListIsEmpty();
verify.completionListContains("toExponential");
goTo.marker("dotOnNumberExrpressions3");
verify.completionListIsEmpty();
verify.completionListContains("toExponential");
goTo.marker("dotOnNumberExrpressions4");
verify.completionListIsEmpty();

View File

@ -3,4 +3,4 @@
////5../**/
goTo.marker();
verify.completionListIsEmpty();
verify.completionListContains("toFixed");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var a = 0;
////a/./**/
goTo.marker();
// should not crash
verify.completionListIsEmpty();

View File

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
////var aa = 1;
//// try {} catch(/*catchVariable1*/
//// try {} catch(a/*catchVariable2*/
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.completionListIsEmpty();
});

View File

@ -0,0 +1,12 @@
/// <reference path='fourslash.ts' />
////var aa = 1;
////class /*className1*/
////class a/*className2*/
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.completionListIsEmpty();
});

View File

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
////var aa = 1;
////enum a { /*enumValueName1*/
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.completionListIsEmpty();
});

View File

@ -0,0 +1,9 @@
/// <reference path='fourslash.ts' />
////var aa = 1;
////enum a { foo, /*enumValueName3*/
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.completionListIsEmpty();
});

View File

@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
////var aa = 1;
////enum /*enumName1*/
////enum a/*enumName2*/
////var x = 0; enum /*enumName4*/
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.completionListIsEmpty();
});

View File

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
////var aa = 1;
////function /*functionName1*/
////function a/*functionName2*/
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.completionListIsEmpty();
});

View File

@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
////var aa = 1;
////interface a { /*interfaceValue1*/
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.completionListIsEmpty();
});

View File

@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
////var aa = 1;
////interface a { f/*interfaceValue2*/
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.completionListIsEmpty();
});

View File

@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
////var aa = 1;
////interface a { f; /*interfaceValue3*/
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.completionListIsEmpty();
});

View File

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
////var aa = 1;
////interface /*interfaceName1*/
////interface a/*interfaceName2*/
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.completionListIsEmpty();
});

View File

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
////var aa = 1;
////module /*moduleName1*/
////module a/*moduleName2*/
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.completionListIsEmpty();
});

View File

@ -1,40 +1,33 @@
/// <reference path='fourslash.ts' />
////var aa = 1;
////class /*className1*/
////class a/*className2*/
////interface /*interfaceName1*/
////interface a/*interfaceName2*/
////module /*moduleName1*/
////module a/*moduleName2*/
////enum /*enumName1*/
////enum a/*enumName2*/
////// fourslash is saying completion list is not empty on this line but editor disagrees
//////enum a { /*enumValueName1*/
////enum a { f/*enumValueName2*/
////enum a { foo, /*enumValueName3*/
////var x = 0; enum /*enumName4*/
////function /*functionName1*/
////function a/*functionName2*/
////var /*varName1*/
////var a/*varName2*/
////var a2,/*varName3*/
////var a2, a/*varName4*/
////function testFunction(/*parameterName1*/
////function testFunction(a/*parameterName2*/
////function testFunction(a, /*parameterName3*/
////function testFunction(a, b/*parameterName4*/
////class bar1{ constructor(/*constructorParamter1*/
////class bar2{ constructor(a/*constructorParamter2*/
////class bar3{ constructor(a, /*constructorParamter3*/
////class bar4{ constructor(a, b/*constructorParamter4*/
////class bar5{ constructor(public /*constructorParamter5*/
////class bar6{ constructor(public a/*constructorParamter6*/
////class bar7{ constructor(private a/*constructorParamter7*/
////class bar8{ constructor(.../*constructorParamter8*/
////class bar9{ constructor(...a/*constructorParamter9*/
//// try {} catch(/*catchVariable1*/
//// try {} catch(a/*catchVariable2*/
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);

View File

@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />
////var aa = 1;
////var /*varName1*/
////var a/*varName2*/
////var a2,/*varName3*/
////var a2, a/*varName4*/
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.completionListIsEmpty();
});

View File

@ -0,0 +1,7 @@
/// <reference path='fourslash.ts' />
//// // */{| "name" : "1" |}
goTo.marker("1");
// Completion list should not be available within comments
verify.completionListIsEmpty();

View File

@ -0,0 +1,31 @@
/// <reference path='fourslash.ts' />
//// /*{| "name": "1" |}
//// /* {| "name": "2" |}
//// /* *{| "name": "3" |}
//// /* */{| "name": "4" |}
//// {| "name": "5" |}/* */
/////* {| "name": "6" |}
goTo.marker("1");
verify.completionListIsEmpty();
goTo.marker("2");
verify.completionListIsEmpty();
goTo.marker("3");
verify.completionListIsEmpty();
goTo.marker("4");
verify.not.completionListIsEmpty();
goTo.marker("5");
verify.not.completionListIsEmpty();
goTo.marker("6");
verify.completionListIsEmpty();

View File

@ -0,0 +1,31 @@
/// <reference path="fourslash.ts"/>
////class Other {
//// public p;
//// protected p2
//// private p3;
////}
////
////class Self {
//// private other: Other;
////
//// method() {
//// this.other./*1*/;
////
//// this.other.p/*2*/;
////
//// this.other.p/*3*/.toString();
//// }
////}
goTo.marker("1");
verify.memberListContains("p");
verify.memberListCount(1);
goTo.marker("2");
verify.memberListContains("p");
verify.memberListCount(1);
goTo.marker("2");
verify.memberListContains("p");
verify.memberListCount(1);

View File

@ -10,6 +10,7 @@
////
//// e./**/
goTo.marker();
verify.not.completionListContains('1');
verify.not.completionListContains('"1"');
verify.not.completionListContains('2');

View File

@ -37,7 +37,7 @@ verify.quickInfoIs("(var) a: {\n (): a1.connectExport;\n test1: a1.connect
goTo.marker('3');
verify.quickInfoIs("(property) test1: a1.connectModule(res: any, req: any, next: any) => void", undefined);
verify.completionListContains("test1", "(property) test1: a1.connectModule", undefined);
verify.completionListContains("test1", "(property) test1: a1.connectModule(res: any, req: any, next: any) => void", undefined);
verify.completionListContains("test2", "(method) test2(): a1.connectModule", undefined);
verify.not.completionListContains("connectModule");
verify.not.completionListContains("connectExport");
@ -59,7 +59,7 @@ verify.quickInfoIs("(var) r2: a1.connectExport", undefined);
goTo.marker('9');
verify.quickInfoIs("(property) test1: a1.connectModule(res: any, req: any, next: any) => void", undefined);
verify.completionListContains("test1", "(property) test1: a1.connectModule", undefined);
verify.completionListContains("test1", "(property) test1: a1.connectModule(res: any, req: any, next: any) => void", undefined);
verify.completionListContains("test2", "(method) test2(): a1.connectModule", undefined);
verify.completionListContains("connectModule");
verify.completionListContains("connectExport");