• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0.
2// See LICENSE.txt in the project root for complete license information.
3
4///<reference path='typescript.ts' />
5
6module TypeScript {
7    export class TypeCollectionContext {
8        public script: Script = null;
9
10        constructor (public scopeChain: ScopeChain, public checker: TypeChecker) {
11        }
12    }
13
14    export class MemberScopeContext {
15        public type: Type = null;
16        public ast: AST = null;
17        public scope: SymbolScope;
18        public options = new AstWalkOptions();
19
20        constructor (public flow: TypeFlow, public pos: number, public matchFlag: ASTFlags) {
21        }
22    }
23
24    export class EnclosingScopeContext {
25
26        public scopeGetter: () => SymbolScope = null;
27        public objectLiteralScopeGetter: () => SymbolScope = null;
28        public scopeStartAST: AST = null;
29        public skipNextFuncDeclForClass = false;
30        public deepestModuleDecl: ModuleDeclaration = null;
31        public enclosingClassDecl: TypeDeclaration = null;
32        public enclosingObjectLit: UnaryExpression = null;
33        public publicsOnly = true;
34        public useFullAst = false;
35        private scriptFragment: Script;
36
37        constructor (public logger: ILogger,
38                    public script: Script,
39                    public text: ISourceText,
40                    public pos: number,
41                    public isMemberCompletion: boolean) {
42        }
43
44        public getScope(): SymbolScope {
45            return this.scopeGetter();
46        }
47
48        public getObjectLiteralScope(): SymbolScope {
49            return this.objectLiteralScopeGetter();
50        }
51
52        public getScopeAST() {
53            return this.scopeStartAST;
54        }
55
56        public getScopePosition() {
57            return this.scopeStartAST.minChar;
58        }
59
60        public getScriptFragmentStartAST(): AST {
61            return this.scopeStartAST;
62        }
63
64        public getScriptFragmentPosition(): number {
65            return this.getScriptFragmentStartAST().minChar;
66        }
67
68        public getScriptFragment(): Script {
69            if (this.scriptFragment == null) {
70                var ast = this.getScriptFragmentStartAST();
71                var minChar = ast.minChar;
72                var limChar = (this.isMemberCompletion ? this.pos : this.pos + 1);
73                this.scriptFragment = TypeScript.quickParse(this.logger, ast, this.text, minChar, limChar, null/*errorCapture*/).Script;
74            }
75            return this.scriptFragment;
76        }
77    }
78
79    export function preFindMemberScope(ast: AST, parent: AST, walker: IAstWalker) {
80        var memScope: MemberScopeContext = walker.state;
81        if (hasFlag(ast.flags, memScope.matchFlag) && ((memScope.pos < 0) || (memScope.pos == ast.limChar))) {
82            memScope.ast = ast;
83            if ((ast.type == null) && (memScope.pos >= 0)) {
84                memScope.flow.inScopeTypeCheck(ast, memScope.scope);
85            }
86            memScope.type = ast.type;
87            memScope.options.stopWalk();
88        }
89        return ast;
90    }
91
92    export function pushTypeCollectionScope(container: Symbol,
93        valueMembers: ScopedMembers,
94        ambientValueMembers: ScopedMembers,
95        enclosedTypes: ScopedMembers,
96        ambientEnclosedTypes: ScopedMembers,
97        context: TypeCollectionContext,
98        thisType: Type,
99        classType: Type,
100        moduleDecl: ModuleDeclaration) {
101        var builder = new SymbolScopeBuilder(valueMembers, ambientValueMembers, enclosedTypes, ambientEnclosedTypes, null, container);
102        var chain: ScopeChain = new ScopeChain(container, context.scopeChain, builder);
103        chain.thisType = thisType;
104        chain.classType = classType;
105        chain.moduleDecl = moduleDecl;
106        context.scopeChain = chain;
107    }
108
109    export function popTypeCollectionScope(context: TypeCollectionContext) {
110        context.scopeChain = context.scopeChain.previous;
111    }
112
113    export function preFindEnclosingScope(ast: AST, parent: AST, walker: IAstWalker) {
114        var context: EnclosingScopeContext = walker.state;
115        var minChar = ast.minChar;
116        var limChar = ast.limChar;
117
118        // Account for the fact completion list may be called at the end of a file which
119        // is has not been fully re-parsed yet.
120        if (ast.nodeType == NodeType.Script && context.pos > limChar)
121            limChar = context.pos;
122
123        if ((minChar <= context.pos) &&
124            (limChar >= context.pos)) {
125            switch (ast.nodeType) {
126                case NodeType.Script:
127                    var script = <Script>ast;
128                    context.scopeGetter = function () {
129                        return script.bod === null ? null : script.bod.enclosingScope;
130                    };
131                    context.scopeStartAST = script;
132                    break;
133
134                case NodeType.ClassDeclaration:
135                    context.scopeGetter = function () {
136                        return (ast.type === null || ast.type.instanceType.containedScope === null) ? null : ast.type.instanceType.containedScope;
137                    };
138                    context.scopeStartAST = ast;
139                    context.enclosingClassDecl = <TypeDeclaration>ast;
140                    break;
141
142                case NodeType.ObjectLit:
143                    var objectLit = <UnaryExpression>ast;
144                    // Only consider target-typed object literals
145                    if (objectLit.targetType) {
146                        context.scopeGetter = function () {
147                            return objectLit.targetType.containedScope;
148                        };
149                        context.objectLiteralScopeGetter = function () {
150                            return objectLit.targetType.memberScope;
151                        }
152                        context.enclosingObjectLit = objectLit;
153                    }
154                    break;
155
156                case NodeType.ModuleDeclaration:
157                    context.deepestModuleDecl = <ModuleDeclaration>ast;
158                    context.scopeGetter = function () {
159                        return ast.type === null ? null : ast.type.containedScope;
160                    };
161                    context.scopeStartAST = ast;
162                    break;
163
164                case NodeType.InterfaceDeclaration:
165                    context.scopeGetter = function () {
166                        return (ast.type === null) ? null : ast.type.containedScope;
167                    };
168                    context.scopeStartAST = ast;
169                    break;
170
171                case NodeType.FuncDecl: {
172                    var funcDecl = <FuncDecl>ast;
173                    if (context.skipNextFuncDeclForClass) {
174                        context.skipNextFuncDeclForClass = false;
175                    }
176                    else {
177                        context.scopeGetter = function () {
178                            // The scope of a class constructor is hidden somewhere we don't expect :-S
179                            if (funcDecl.isConstructor && hasFlag(funcDecl.fncFlags, FncFlags.ClassMethod)) {
180                                if (ast.type && ast.type.enclosingType) {
181                                    return ast.type.enclosingType.constructorScope;
182                                }
183                            }
184
185                            if (funcDecl.scopeType) {
186                                return funcDecl.scopeType.containedScope;
187                            }
188
189                            if (funcDecl.type) {
190                                return funcDecl.type.containedScope;
191                            }
192                            return null;
193                        };
194                        context.scopeStartAST = ast;
195                    }
196                }
197                    break;
198            }
199            walker.options.goChildren = true;
200        }
201        else {
202            walker.options.goChildren = false;
203        }
204        return ast;
205    }
206
207    //
208    // Find the enclosing scope context from a position inside a script AST.
209    // The "scopeStartAST" of the returned scope is always valid.
210    // Return "null" if the enclosing scope can't be found.
211    //
212    export function findEnclosingScopeAt(logger: ILogger, script: Script, text: ISourceText, pos: number, isMemberCompletion: boolean): EnclosingScopeContext {
213        var context = new EnclosingScopeContext(logger, script, text, pos, isMemberCompletion);
214
215        TypeScript.getAstWalkerFactory().walk(script, preFindEnclosingScope, null, null, context);
216
217        if (context.scopeStartAST === null)
218            return null;
219        return context;
220    }
221}