function getDocCommentTemplateAtPosition(fileName, position) {
            var start = new Date().getTime();
            var sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
            // Check if in a context where we don't want to perform any insertion
            if (ts.isInString(sourceFile, position) || ts.isInComment(sourceFile, position) || ts.hasDocComment(sourceFile, position)) {
                return undefined;
            }
            var tokenAtPos = ts.getTokenAtPosition(sourceFile, position);
            var tokenStart = tokenAtPos.getStart();
            if (!tokenAtPos || tokenStart < position) {
                return undefined;
            }
            // TODO: add support for:
            // - enums/enum members
            // - interfaces
            // - property declarations
            // - potentially property assignments
            var commentOwner;
            findOwner: for (commentOwner = tokenAtPos; commentOwner; commentOwner = commentOwner.parent) {
                switch (commentOwner.kind) {
                    case 213 /* FunctionDeclaration */:
                    case 143 /* MethodDeclaration */:
                    case 144 /* Constructor */:
                    case 214 /* ClassDeclaration */:
                    case 193 /* VariableStatement */:
                        break findOwner;
                    case 248 /* SourceFile */:
                        return undefined;
                    case 218 /* ModuleDeclaration */:
                        // If in walking up the tree, we hit a a nested namespace declaration,
                        // then we must be somewhere within a dotted namespace name; however we don't
                        // want to give back a JSDoc template for the 'b' or 'c' in 'namespace a.b.c { }'.
                        if (commentOwner.parent.kind === 218 /* ModuleDeclaration */) {
                            return undefined;
                        }
                        break findOwner;
                }
            }
            if (!commentOwner || commentOwner.getStart() < position) {
                return undefined;
            }
            var parameters = getParametersForJsDocOwningNode(commentOwner);
            var posLineAndChar = sourceFile.getLineAndCharacterOfPosition(position);
            var lineStart = sourceFile.getLineStarts()[posLineAndChar.line];
            var indentationStr = sourceFile.text.substr(lineStart, posLineAndChar.character);
            // TODO: call a helper method instead once PR #4133 gets merged in.
            var newLine = host.getNewLine ? host.getNewLine() : "\r\n";
            var docParams = "";
            for (var i = 0, numParams = parameters.length; i < numParams; i++) {
                var currentName = parameters[i].name;
                var paramName = currentName.kind === 69 /* Identifier */ ?
                    currentName.text :
                    "param" + i;
                docParams += indentationStr + " * @param " + paramName + newLine;
            }
            // A doc comment consists of the following
            // * The opening comment line
            // * the first line (without a param) for the object's untagged info (this is also where the caret ends up)
            // * the '@param'-tagged lines
            // * TODO: other tags.
            // * the closing comment line
            // * if the caret was directly in front of the object, then we add an extra line and indentation.
            var preamble = "/**" + newLine +
                indentationStr + " * ";
            var result = preamble + newLine +
                docParams +
                indentationStr + " */" +
                (tokenStart === position ? newLine + indentationStr : "");
            return { newText: result, caretOffset: preamble.length };
        }
Checks if position points to a valid position to add JSDoc comments, and if so,
returns the appropriate template. Otherwise returns an empty string.
Valid positions are
     - outside of comments, statements, and expressions, and
     - preceding a:
         - function/constructor/method declaration
         - class declarations
         - variable statements
         - namespace declarations

Hosts should ideally check that:
- The line is all whitespace up to 'position' before performing the insertion.
- If the keystroke sequence "/\*\*" induced the call, we also check that the next
non-whitespace character is '*', which (approximately) indicates whether we added
the second '*' to complete an existing (JSDoc) comment.
@param fileName The file in which to perform the check.
@param position The (character-indexed) position in the file where the check should
be performed.